简体   繁体   中英

There is already an open DataReader associated with this Command, without nested datareaders

I'm getting the following error intermittently. There is already an open DataReader associated with this Command which must be closed first.

I read that this can happens when there are nested DataReaders in the same connection, but in my case, I'm using the following code to execute all queries.

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

This way, The result is stored in an object and there isn't nested readers. I also read that adding 'MultipleActiveResultSets=True' to connection string can solve the problem when using nested readers. Does this solution also solve my problem? As the error is intermitent and only happens in production environment, I can't test it many times.

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

The problem was that, when a query fails, the transaction can't be rolled back because the data reader is already open to process the query.

A second exception is thrown and the first one is lost.

I just placed the rollback inside a try catch block and used the AggregateException class to throw both exceptions.

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

Although the transaction will be rolled back anyway, I think you can also try to close the data reader before the rollback, so it will probably work.

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

Since this happens only on production it's more likely that bug is outside the code you attached.

Most common way to prevent this is to always code in following fashion:

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

Notice the finally block, it makes sure reader is closed no matter what. I am under impression that something happens in your code that leaves the reader open but the bug isn't visible in the code you've posted.

I recommend you enclose it in the above try/finally block and your bug is quite likely to be resolved .

Edit, to clarify: This may not resolve whatever bug exists outside the scope of the originally shown code but it will prevent data readers being left open. The finally block I suggested won't block any exceptions, they will be propagated to whatever handler you employ outside of it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM