错误’已经有一个与此命令关联的打开的datareader,必须先关闭’

运行时错误’已经有一个与此命令关联的打开的datareader,必须先关闭’

objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn); objDataReader = objCommand.ExecuteReader(); while (objDataReader.Read()) { objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + objDataReader[0] + "')", objConn); objInsertCommand.ExecuteNonQuery();//Here is the error } objDataReader.Close(); 

我不能在这里定义任何存储过程。 任何帮助我们都会感激。

如何通过Fill将数据拉入DataSet,然后遍历它以通过NonQuery执行插入?

 IDbDataAdapter da; IDbCommand selectCommand = connection.CreateCommand(); selectCommand.CommandType = CommandType.Text; selectCommand.CommandText = "SELECT field1, field2 FROM sourcetable"; connection.Open(); DataSet selectResults= new DataSet(); da.Fill(selectResults); // get dataset selectCommand.Dispose(); IDbCommand insertCommand; foreach(DataRow row in selectResults.Tables[0].Rows) { insertCommand = connection.CreateCommand(); insertCommand.CommandType = CommandType.Text; insertCommand.CommandText = "INSERT INTO tablename (field1, field2) VALUES (3, '" + row["columnName"].ToString() + "'"; } insertCommand.Dispose(); connection.Close(); 

不需要做所有这些,只需打开MARS,您的问题就会得到解决。 在你的连接字符串中只需添加MultipleActiveResultSets=True;

当它仍然在读取数据读取器的内容时​​,您无法对该连接执行操作 – 该错误非常具有描述性。

您的替代方案是:

1)首先使用DataSet检索所有数据,或者使用阅读器填充其他一些集合,然后在初始选择完成后立即运行所有数据。

2)为insert语句使用不同的连接。

您最好的选择是将所需信息读入列表,然后迭代列表以执行插入,如下所示:

  List values = new List(); using(SqlCommand objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn)) { using(SqlDataReader objDataReader = objCommand.ExecuteReader()) { while(objDataReader.Read()) { values.Add(objDataReader[0].ToString()); } } } foreach(String value in values) { using(SqlCommand objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + value + "')", objConn)) { objInsertCommand.ExecuteNonQuery(); } } 
 INSERT INTO tablename (field1, field2) SELECT 3, field1 FROM sourcetable 

单个SQL语句,而不是每个插入一个。 不确定这是否适用于您的实际问题,但对于您提供的示例,这比一次执行一个查询要好得多。

另外,请确保您的代码使用参数化查询,而不是在SQL语句中按原样接受字符串 – 您的示例对SQL注入开放。

提出了一些有效的建议,以及改进实施的建议。 由于现有代码没有清理读卡器,我达到了MARS限制,所以我想把一个更可敬的样本放在一起:

 const string connectionString = @"server=.\sqlexpress;database=adventureworkslt;integrated security=true"; const bool useMARS = false; using (var objConn = new System.Data.SqlClient.SqlConnection(connectionString + (useMARS ? ";MultipleActiveResultSets=True" : String.Empty))) using (var objInsertConn = useMARS ? null : new System.Data.SqlClient.SqlConnection(connectionString)) { objConn.Open(); if (objInsertConn != null) { objInsertConn.Open(); } using (var testCmd = new System.Data.SqlClient.SqlCommand()) { testCmd.Connection = objConn; testCmd.CommandText = @"if not exists(select 1 from information_schema.tables where table_name = 'sourcetable') begin create table sourcetable (field1 int, field2 varchar(5)) insert into sourcetable values (1, 'one') create table tablename (field1 int, field2 varchar(5)) end"; testCmd.ExecuteNonQuery(); } using (var objCommand = new System.Data.SqlClient.SqlCommand("SELECT field1, field2 FROM sourcetable", objConn)) using (var objDataReader = objCommand.ExecuteReader()) using (var objInsertCommand = new System.Data.SqlClient.SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, @field2)", objInsertConn ?? objConn)) { objInsertCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("field2", String.Empty)); while (objDataReader.Read()) { objInsertCommand.Parameters[0].Value = objDataReader[0]; objInsertCommand.ExecuteNonQuery(); } } } 

您使用的是哪个版本的SQL Server? 问题可能在于此:

(来自http://msdn.microsoft.com/en-us/library/9kcbe65k.aspx )

在SQL Server 2005之前使用SQL Server版本时,在使用SqlDataReader时,关联的SqlConnection正忙于为SqlDataReader提供服务。 在此状态下,除了关闭它之外,不能对SqlConnection执行任何其他操作。 在调用SqlDataReader的Close方法之前就是这种情况。

因此,如果这是导致问题的原因,则应首先读取所有数据,然后关闭SqlDataReader,然后才执行插入。

就像是:

 objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn); objDataReader = objCommand.ExecuteReader(); List values = new List(); while (objDataReader.Read()) { values.Add(objDataReader[0]); } objDataReader.Close(); foreach (object value in values) { objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + value + "')", objConn); objInsertCommand.ExecuteNonQuery(); } 

将此添加到连接字符串应该可以解决问题。

 MultipleActiveResultSets=true 

选项1:必须在运行另一个查询之前执行查询和加载数据。

选项2:MultipleActiveResultSets=true添加到连接字符串的提供者部分。 请参阅以下示例:

  

尝试这样的事情:

 //Add a second connection based on the first one SqlConnection objConn2= new SqlConnection(objConn.connectionString)) SqlCommand objInsertCommand= new SqlCommand(); objInsertCommand.CommandType = CommandType.Text; objInsertCommand.Connection = objConn2; while (objDataReader.Read()) { objInsertCommand.CommandText = "INSERT INTO tablename (field1, field2) VALUES (3, '" + objDataReader[0] + "')"; objInsertCommand.ExecuteNonQuery(); } 

最佳解决方案:“CommandText”值只有问题。 让它成为SP或普通的Sql Query。

  • 检查1:您在Sql Query中传递的参数值没有变化,并且在ExecuteReader中反复出现。

  • 检查2:错误地形成了Sql Query字符串。

  • 检查3:请按如下方式创建最简单的代码。

     string ID = "C8CA7EE2"; string myQuery = "select * from ContactBase where contactid=" + "'" + ID + "'"; string connectionString = ConfigurationManager.ConnectionStrings["CRM_SQL_CONN_UAT"].ToString(); SqlConnection con = new SqlConnection(connectionString); con.Open(); SqlCommand cmd = new SqlCommand(myQuery, con); DataTable dt = new DataTable(); dt.Load(cmd.ExecuteReader()); con.Close(); 

为了便于处理,我使用以下编码模板:

 `using (SqlConnection connection = new SqlConnection("your connection string")) { connection.Open(); using (SqlCommand cmd = connection.CreateCommand()) { cmd.CommandText = "Select * from SomeTable"; using (SqlDataReader reader = cmd.ExecuteReader()) { if(reader.HasRows) { while(reader.Read()){ // assuming that we've a 1-column(Id) table int id = int.Parse(reader[0].ToString()); } } } } connection.Close() }`