我的代码:
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();
?
答案 0 :(得分:3)
只要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注入攻击,并且不是很好的做法 - 您最好使用Parameter而不是为原始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();
});
答案 1 :(得分:1)
您已经有一个与“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();
所以就像上面给出的那样,为插入创建一个新命令。
答案 2 :(得分:1)
这个单一查询应该完成这项工作(不确定您是否准确的数据模型,如果需要,可以调整):
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();
答案 3 :(得分:1)
您可以更改连接字符串,而不是使用第二个连接对象,并使用MARS(Multiple active result set)来实现此目的。将以下语句添加到连接字符串:
MultipleActiveResultSets=True
编辑: 和其他人说的那样,使用SqlParameters作为参数而不是字符串连接。这不仅是一个安全问题,而且还有巨大的性能损失!
答案 4 :(得分:0)
您需要声明一个新的命令对象,因为当您尝试将其用于insert语句时,cmd
已用于读取数据。另外,不要使用sql命令中的字符串连接,这是一种不好的做法,容易受到SQL注入攻击。使用参数。