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.