必须关闭 asp.net datareader

发布于 2024-12-20 22:32:33 字数 746 浏览 3 评论 0原文

我的代码:

SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString);
SqlCommand cmd = new SqlCommand();
//..........
cmd.CommandText = "SELECT * FROM TempQn WHERE creatorId=  '" +
Session["administratorID"].ToString() + "'";  
dr = cmd.ExecuteReader();  
while (dr.Read())
{
    int ids = Int32.Parse(dr["QuestionID"].ToString());
    cmd.CommandText = " INSERT INTO Answers (QuestionId,Answer) Select c.QnId, c.Answer From TempAns c Where c.Id = " + ids + " ";
    cmd.ExecuteNonQuery(); //this line
}
dr.Close();

错误是:

已经有一个打开的 DataReader 与此命令关联,必须先将其关闭。

什么样的命令应该替换cmd.ExecuteNonQuery();

My code:

SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString);
SqlCommand cmd = new SqlCommand();
//..........
cmd.CommandText = "SELECT * FROM TempQn WHERE creatorId=  '" +
Session["administratorID"].ToString() + "'";  
dr = cmd.ExecuteReader();  
while (dr.Read())
{
    int ids = Int32.Parse(dr["QuestionID"].ToString());
    cmd.CommandText = " INSERT INTO Answers (QuestionId,Answer) Select c.QnId, c.Answer From TempAns c Where c.Id = " + ids + " ";
    cmd.ExecuteNonQuery(); //this line
}
dr.Close();

The error is:

There is already an open DataReader associated with this Command which must be closed first.

What kind of command should replace the cmd.ExecuteNonQuery();?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

半步萧音过轻尘 2024-12-27 22:32:33

只要 DataReader 处于“活动”状态,您就无法执行任何进一步的 SQL 语句。

为了克服这个问题,请存储 SQL 语句列表,然后在阅读以下内容后执行它们:

cmd.CommandText = "SELECT * FROM Question WHERE SurveyID= '" + sID + "'";    
dr = cmd.ExecuteReader();  
List<string> arrSQL = new List<string>();
while (dr.Read())
{
    int ids = Int32.Parse(dr["QuestionID"].ToString());
    arrSQL.Add("INSERT INTO Answers (QuestionId,Answer) Select c.QnId, c.Answer From TempAns c Where c.Id = " + ids + " ");
}
dr.Close();

arrSQL.ForEach(strSQL =>
{
    cmd.CommandText = strSQL;
    cmd.ExecuteNonQuery();
});

您当前的代码很容易受到 SQL 注入攻击,但这不是一个好的做法 - 您最好使用参数而不是向原始 SQL 注入值 - 以下是如何实现这一点:

cmd.CommandText = "SELECT * FROM Question WHERE SurveyID=@id";
cmd.Parameters.AddWithValue("@id", sID);
dr = cmd.ExecuteReader();  
List<int> arrQuestions = new List<int>();
while (dr.Read())
{
    int ids = Int32.Parse(dr["QuestionID"].ToString());
    arrQuestions.Add(ids);
}
dr.Close();

cmd.CommandText =  "INSERT INTO Answers (QuestionId, Answer) Select c.QnId, c.Answer From TempAns c Where c.Id = @id";
arrQuestions.ForEach(id =>
{
    cmd.Parameters["@id"].Value = id;
    cmd.ExecuteNonQuery();
});

You can't execute any further SQL statements as long as the DataReader is "active".

To overcome this, store list of the SQL statements then exeucute them after reading:

cmd.CommandText = "SELECT * FROM Question WHERE SurveyID= '" + sID + "'";    
dr = cmd.ExecuteReader();  
List<string> arrSQL = new List<string>();
while (dr.Read())
{
    int ids = Int32.Parse(dr["QuestionID"].ToString());
    arrSQL.Add("INSERT INTO Answers (QuestionId,Answer) Select c.QnId, c.Answer From TempAns c Where c.Id = " + ids + " ");
}
dr.Close();

arrSQL.ForEach(strSQL =>
{
    cmd.CommandText = strSQL;
    cmd.ExecuteNonQuery();
});

Your current code is vulnerable to SQL injection attacks though and isn't good practice - you better use Parameter instead of injecting value to the raw SQL - here is how to achieve that:

cmd.CommandText = "SELECT * FROM Question WHERE SurveyID=@id";
cmd.Parameters.AddWithValue("@id", sID);
dr = cmd.ExecuteReader();  
List<int> arrQuestions = new List<int>();
while (dr.Read())
{
    int ids = Int32.Parse(dr["QuestionID"].ToString());
    arrQuestions.Add(ids);
}
dr.Close();

cmd.CommandText =  "INSERT INTO Answers (QuestionId, Answer) Select c.QnId, c.Answer From TempAns c Where c.Id = @id";
arrQuestions.ForEach(id =>
{
    cmd.Parameters["@id"].Value = id;
    cmd.ExecuteNonQuery();
});
影子是时光的心 2024-12-27 22:32:33

您已经有一个与“cmd”关联的命令。

  dr = cmd.ExecuteReader();  
          while (dr.Read())
          {
              int ids = Int32.Parse(dr["QuestionID"].ToString());
              SqlCommand sqlCmd = new SqlCommand("INSERT INTO Answers (QuestionId,Answer) Select c.QnId, c.Answer From TempAns c Where c.Id = " + ids + " ");
              sqlCmd.ExecuteNonQuery(); //this line
          }
          dr.Close();

因此,就像上面给出的那样,创建一个新的插入命令。

You already have one command associated with "cmd".

  dr = cmd.ExecuteReader();  
          while (dr.Read())
          {
              int ids = Int32.Parse(dr["QuestionID"].ToString());
              SqlCommand sqlCmd = new SqlCommand("INSERT INTO Answers (QuestionId,Answer) Select c.QnId, c.Answer From TempAns c Where c.Id = " + ids + " ");
              sqlCmd.ExecuteNonQuery(); //this line
          }
          dr.Close();

So Like ive given above create a new command for the insertion.

昇り龍 2024-12-27 22:32:33

这个单个查询应该可以完成这项工作(不确定您确切的数据模型,请根据需要进行调整):

INSERT INTO Answers (QuestionId,Answer) 
Select c.QnId, c.Answer 
From TempAns c 
inner join Question q on c.QnId = q.Id
where q.SurveyID = @SurveyID

为了避免 SQl 注入,请使用以下 C# 代码:

cmd.CommandTest = @"INSERT INTO Answers (QuestionId,Answer) 
    Select c.QnId, c.Answer 
    From TempAns c 
    inner join Question q on c.QnId = q.Id
    where q.SurveyID = @SurveyID";

SqlParameter param = cmd.Parameters.Add("@SurveyID", SqlDbType.Int);
param.Value = yourSurveyId;

cmd.Open(); // it would be better to check the status before 
cmd.ExecuteNonQuery();
cmd.Close();

This single query should do the job (not sure of you exact data model, adapt if required ):

INSERT INTO Answers (QuestionId,Answer) 
Select c.QnId, c.Answer 
From TempAns c 
inner join Question q on c.QnId = q.Id
where q.SurveyID = @SurveyID

In order to avoid SQl Injection, use this C# code :

cmd.CommandTest = @"INSERT INTO Answers (QuestionId,Answer) 
    Select c.QnId, c.Answer 
    From TempAns c 
    inner join Question q on c.QnId = q.Id
    where q.SurveyID = @SurveyID";

SqlParameter param = cmd.Parameters.Add("@SurveyID", SqlDbType.Int);
param.Value = yourSurveyId;

cmd.Open(); // it would be better to check the status before 
cmd.ExecuteNonQuery();
cmd.Close();
勿忘初心 2024-12-27 22:32:33

您可以更改连接字符串并使用 MARS (多个活动结果集) 用于此目的。将以下语句添加到您的连接字符串:

MultipleActiveResultSets=True

编辑:
就像其他人所说的那样,使用 SqlParameters 作为参数,而不是字符串连接。这不仅是一个安全问题,而且还会对性能造成巨大影响!

Instead of using a 2nd connection object, you could change your connection string and use MARS (Multiple active result set) for this purpose. Add the following statement to your connection string:

MultipleActiveResultSets=True

EDIT:
And like the other's said, use SqlParameters for your parameters and not string concatenation. It's not only a security issue, but also a huge performance hit!

还给你自由 2024-12-27 22:32:33

您需要声明一个新的命令对象,因为当您尝试将其用于插入语句时, cmd 已被用于读取数据。另外,不要使用 sql 命令中的字符串连接,这是一种不好的做法,并且容易受到 SQL 注入的攻击。使用参数。

you need to declare a new command object because cmd is already being used for reading the data when you are trying to use it for insert statement. Also, don't use string concatenation from sql command, its a bad practice and vulnerable to SQL injection. using parameters.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文