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

C# 错误“已经有一个打开的datareader与此命令关联,必须先关闭”,c#,ado.net,C#,Ado.net,运行时错误“已经有一个打开的datareader与此命令关联,必须先关闭” objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn); objDataReader = objCommand.ExecuteReader(); while (objDataReader.Read()) { objInsertCommand = new SqlCommand("INSERT INTO tablenam

运行时错误“已经有一个打开的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将数据拉入数据集,然后通过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();

试着这样做:

//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();
}

您使用的是什么版本的SQL Server?问题可能在于:

当您使用SQLServer2005之前的SQLServer版本时,在使用SqlDataReader时,关联的SqlConnection正忙于为SqlDataReader提供服务。在这种状态下,除了关闭SqlConnection之外,不能对SqlConnection执行其他操作。在调用SqlDataReader的Close方法之前都是这样

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

比如:

objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn);

objDataReader = objCommand.ExecuteReader();

List<object> values = new List<object>();
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();
}

当连接仍在读取数据读取器的内容时,您不能对该连接执行操作-错误是非常描述性的

你的选择是:

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


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

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

        List<String> values = new List<String>();
        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();
            }
        }
一个SQL语句,而不是每个插入一个SQL语句。不确定这是否适用于您的实际问题,但对于您提供的示例,这是一个比一次执行一个查询要好得多的查询


另一方面,请确保您的代码使用参数化查询,而不是接受SQL语句中的字符串-您的示例可以接受SQL注入。

无需执行所有这些操作,只需打开MARS,您的问题就会得到解决。在连接字符串中,只需添加MultipleActiveResultSets=True

已经给出了一些非常有效的建议,以及改进实施的建议。由于现有代码没有清理读卡器,我达到了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();
  }
 }
}

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

MultipleActiveResultSets=true
最佳解决方案: CommandText值只有一个问题。让它成为SP或普通Sql查询

检查1:在Sql查询中传递的参数值 在你的ExecuteReader中不会一次又一次地改变和前进

检查2:Sql查询字符串格式错误

检查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()
        }`
备选案文1: 在运行另一个查询之前,必须执行查询并加载数据

备选案文2: 将MultipleActiveResultSets=true添加到连接字符串的提供程序部分。请参见下面的示例:

<add name="DbContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />

你能给我提供语法或示例吗?这不起作用-这与OP已经在做的事情是一样的。+1是到目前为止唯一的答案,它安全地处理了命令,并用SQL 2008将其重新格式化。对我有用。SQLServer2008。适合我。在CLR过程中使用context connection=true时无法使用SQL Server 2008.MARS:请参阅在执行reader之前是否打开了连接?你确定你读取的数据正确吗?我已经更新了我的答案,如果它仍然不能正常工作,请上传你的代码,以便我能提供更多帮助
<add name="DbContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />