¿Es necesario utilizar try-finally
o la using
-statement disponer el SqlTransaction
?
No hace daño tenerlo. Esto es cierto para cada clase que implementa IDisposable, de lo contrario no implementaría esta interfaz.
Pero normalmente el recolector de basura trataría con él si el objeto ya no se referencia. Como tampoco quiero llamar al dispose
en cada segunda variable ni utilizar el using-statement en todas partes, siempre vale la pena examinar la implementación real del método de clase 'Dispose
'.
SqlTransaction.Dispose
:
protected override void Dispose(bool disposing)
{
if (disposing)
{
SNIHandle target = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
target = SqlInternalConnection.GetBestEffortCleanupTarget(this._connection);
if (!this.IsZombied && !this.IsYukonPartialZombie)
{
this._internalTransaction.Dispose();
}
}
catch (OutOfMemoryException e)
{
this._connection.Abort(e);
throw;
}
catch (StackOverflowException e2)
{
this._connection.Abort(e2);
throw;
}
catch (ThreadAbortException e3)
{
this._connection.Abort(e3);
SqlInternalConnection.BestEffortCleanup(target);
throw;
}
}
base.Dispose(disposing);
}
Sin la comprensión de todos (o nada) lo que está sucediendo aquí puedo decir que esto es más que un simple base.Dispose(disposing)
. Por lo tanto, podría ser una buena idea asegurarse de que se elimine una SqlTransaction.
Pero debido SqlConnection.BeginTransaction
crea la transacción también podría ser una buena idea para reflect esto también:
public SqlTransaction BeginTransaction(IsolationLevel iso, string transactionName)
{
SqlStatistics statistics = null;
string a = ADP.IsEmpty(transactionName) ? "None" : transactionName;
IntPtr intPtr;
Bid.ScopeEnter(out intPtr, "<sc.SqlConnection.BeginTransaction|API> %d#, iso=%d{ds.IsolationLevel}, transactionName='%ls'\n", this.ObjectID, (int)iso, a);
SqlTransaction result;
try
{
statistics = SqlStatistics.StartTimer(this.Statistics);
SqlTransaction sqlTransaction = this.GetOpenConnection().BeginSqlTransaction(iso, transactionName);
GC.KeepAlive(this);
result = sqlTransaction;
}
finally
{
Bid.ScopeLeave(ref intPtr);
SqlStatistics.StopTimer(statistics);
}
return result;
}
Como se puede ver. El GC también mantendrá la conexión activa cuando se crea una transacción. Tampoco contiene una referencia a la transacción ya que solo la devuelve. Por lo tanto, podría no eliminarse incluso cuando la conexión ya esté dispuesta. Otro argumento para deshacerse de la transacción.
También puede consultar el TransactionScope
class que es más a prueba de fallas que BeginTransaction
. Eche un vistazo a this question para obtener más información.
no hace daño tenerlo. – Brian
Si no está utilizando un 'using' alrededor de' sqlTrans' entonces ciertamente no hace daño llamar explícitamente a 'Dispose()' en él. –
@Cory ¿Es necesario comprobar si sqlTrans ya está dispuesto antes de llamar a sqlTrans.Dispose()? – Lijo