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

时间:2010-10-01 13:25:13

标签: c# ado.net

运行时错误'已经有一个与此命令关联的打开的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();

我无法在此定义任何存储过程。 任何帮助我们都会感激。

12 个答案:

答案 0 :(得分:80)

无需完成所有操作,只需启用MARS即可解决问题。在您的连接字符串中,只需添加MultipleActiveResultSets=True;

即可

答案 1 :(得分:7)

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

您的替代方案是:

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

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

答案 2 :(得分:6)

如何通过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();

答案 3 :(得分:4)

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

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

答案 4 :(得分:3)

INSERT INTO tablename (field1, field2)
    SELECT 3, field1 FROM sourcetable

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

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

答案 5 :(得分:2)

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

答案 6 :(得分:1)

您使用的是哪个版本的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<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();
}

答案 7 :(得分:1)

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

MultipleActiveResultSets=true

答案 8 :(得分:1)

选项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" />

答案 9 :(得分:0)

尝试这样的事情:

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

答案 10 :(得分:0)

最佳解决方案: 您的&#34; CommandText&#34;只会出现问题。值。让它成为SP或普通的Sql Query。

  • 检查1:您在Sql Query中传递的参数值 在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();
    

答案 11 :(得分:0)

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

`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()
        }`