已经有一个与此命令关联的开放DataReader,没有嵌套的数据引导器

时间:2015-03-10 20:29:42

标签: c# asp.net ado.net database-connection

我间歇性地收到以下错误。 已经有一个与此命令关联的打开DataReader,必须先关闭它。

我读到,当同一连接中存在嵌套的DataReader时会发生这种情况,但就我而言,我使用以下代码执行所有查询。

    private SqlTransaction Transaction { get; set; }
    private SqlConnection Connection { get; set; }
    private DbRow Row {get; set;}

    public Row Exec(string sql){
        try{
            //Begin connection/transaction
            Connection = new SqlConnection(connectionString);
            Connection.Open();
            Transaction = Connection.BeginTransaction("SampleTransaction");  

            //create command
            SqlCommand command = new SqlCommand(sql, Connection);
            command.Transaction = Transaction;

            //execute reader and close it
            //HERE IS THE PROBLEM, THE READER ALWAYS READ UNTIL THE END
            //BEFORE ANOTHER CAN BE OPENED
            reader = command.ExecuteReader();                
            while (reader.Read())
            {
                object[] value = new object[reader.FieldCount];
                reader.GetValues(value);
                List<object> values = new List<object>(value);                    
                Rows.Add(values);
            }                
            reader.Close();
            Transaction.Commit();
            Connection.Dispose();
            Connection = null;
        }
        catch
        {
           Transaction.Rollback();
           Connection.Dispose();
           Connection = null;
        }
        finally
        {
            if (reader != null && !reader.IsClosed) reader.Close();
        }
    }

这样,结果存储在一个对象中,并没有嵌套的阅读器。 我还读到添加&#39; MultipleActiveResultSets = True&#39;连接字符串可以解决使用嵌套读者时的问题。 这个解决方案也解决了我的问题吗? 由于错误是间歇性的,只发生在生产环境中,我无法多次测试。

There is already an open DataReader associated with this Command which must be closed first. at 
          System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command) at 

System.Data.SqlClient.SqlInternalTransaction.Rollback() at

System.Data.SqlClient.SqlTransaction.Rollback() at 

Application.Lib.DB.DBSQLServer.Rollback()
 at Application.Lib.DB.DBSQLServer.Execute(String sql, Dictionary`2 parameters, 

Nullable`1 timeout, Boolean useTransaction) at 

Application.UtilDB.Execute(String sql, Dictionary`2 parameters, Nullable`1 

timeout, Boolean useTransaction) in c:\Application\DBUtil.cs:line 37 at 

Application.A.CollectionFromDataBase(Int32 cenId, 

IDB db, Int32 includeId, Boolean allStatus) in c:\Application\Activities.cs:line 64 at

Application.ActivitiesController.CheckForConflictsBeforeSave(String aulId, String insId) in c:\Application\AlocController.cs:line 212

2 个答案:

答案 0 :(得分:2)

问题在于,当查询失败时,无法回滚事务,因为数据阅读器已经打开以处理查询。

抛出第二个异常,第一个异常丢失。

我只是将回滚放在try catch块中,并使用AggregateException类抛出两个异常。

try
{
    Transaction.Rollback();
    Connection.Dispose();
    Connection = null;
}
catch (Exception ex2)
{                                                      
    throw new AggregateException(new List<Exception>() { e, ex2 });
}

虽然交易将会回滚,但我认为你也可以尝试在回滚之前关闭数据阅读器,这样它可能会有效。

if (reader != null && !reader.IsClosed) 
    reader.Close();
Transaction.Rollback();

答案 1 :(得分:1)

由于这种情况仅在生产时发生,因此错误更可能在您附加的代码之外。

防止这种情况的最常见方法是始终以下列方式编码:

reader = command.ExecuteReader();
try
{
        for (int i = 0; i < reader.FieldCount; i++)
        {
            dbResult.Columns.Add(reader.GetName(i));
            dbResult.Types.Add(reader.GetDataTypeName(i));
        }
        while (reader.Read())
        {
            object[] value = new object[reader.FieldCount];
            reader.GetValues(value);
            List<object> values = new List<object>(value);                    
            Rows.Add(values);
        }                            
}
finally
{
    reader.Close();
}

注意finally块,它确保读者无论如何都会被关闭。我的印象是,您的代码中发生了一些事情,导致读者处于打开状态但该错误在您发布的代码中不可见。

我建议你将它包含在上面的try / finally块中,你的bug很可能被解决

编辑,澄清:这可能无法解决原始显示的代码范围之外存在的任何错误,但它会阻止数据读取器保持打开状态。我建议的finally块不会阻止任何异常,它们将被传播到您在其外部使用的任何处理程序。