múltiples sqltransactions en solo SQLConnection
-
01-10-2019 - |
Pregunta
Tengo un código que quiero para ejecutar la siguiente manera. Pero me siguen dando la excepción "Este SqlTransaction ha completado, y ya no es utilizable" en la segunda iteración. Es posible que alguien me ayude señalar lo que estoy haciendo mal aquí? Gracias!
SqlConnection cn = (SqlConnection)SqlConnectionManager.Instance.GetUserConnection(user);
cn.Open();
try
{
foreach (Master mRecord in masterList)
{
if (sqlTransaction == null)
sqlTransaction = cn.BeginTransaction();
SqlCommand cm = cn.CreateCommand();
cm.Transaction = sqlTransaction;
cm.CommandType = CommandType.StoredProcedure;
cm.CommandText = "pr_InsertRecords";
try
{
cm.ExecuteNonQuery();
Debug.WriteLine("Auditor.Write: end sql table value param");
sqlTransaction.Commit();
sqlTransaction.Dispose();
}
catch (Exception Ex)
{
Debug.WriteLine(" Exception message: " + Ex.Message);
if (Ex.InnerException != null)
{
Debug.WriteLine("Inner exception message" + Ex.InnerException.Message);
}
sqlTransaction.Rollback();
}
}
}
finally
{
cn.Close();
}
Solución
Dentro del bucle se confirma o retrotrae, pero no restablece la referencia a null
. SqlTransaction
en general no se utiliza como este, se utiliza en un bloque using()
, tal como un SqlConnection
es:
using (SqlConnection cn = SqlConnectionManager.Instance.GetUserConnection(user))
{
foreach (Master mRecord in masterList)
{
try
{
using (SqlTransaction sqlTransaction = cn.BeginTransaction())
{
using (SqlCommand cm = cn.CreateCommand())
{
cm.Transaction = sqlTransaction;
cm.CommandType = CommandType.StoredProcedure;
cm.CommandText = "pr_InsertRecords";
cm.ExecuteNonQuery();
}
sqlTransaction.Commit();
Debug.WriteLine("Auditor.Write: end sql table value param");
}
}
catch (Exception Ex)
{
Debug.WriteLine(" Exception message: " + Ex.Message);
}
}
Otros consejos
Trate de establecer el objeto de sqlTransaction
nula después de desechar la misma. Nota al margen, que realmente debería estar envolviendo esos objetos IDisposable
en el uso de los bloques para Dispose
se llama en todo momento.
sqlTransaction.Commit();
sqlTransaction.Dispose();
sqlTransaction = null;
Se necesita crear un nuevo objeto SqlTransaction
en cada iteración o mover la transacción por completo fuera del bucle si quieren todas las operaciones dentro del bucle que se produzca en una sola transacción. Una vez que se compromete una transacción, es necesario llamar BeginTransaction de nuevo en la conexión para comenzar una nueva. No se puede volver a utilizar el objeto de transacción de edad.