transaction transacciones practices net mvc framework best asp c# sql-server entity-framework transactions entity-framework-6

c# - transacciones - Reversión de transacción de Entity Framework 6



transaction entity framework 5 (3)

Con EF6 tienes una nueva transacción que se puede usar como:

using (var context = new PostEntityContainer()) { using (var dbcxtransaction = context.Database.BeginTransaction()) { try { PostInformation NewPost = new PostInformation() { PostId = 101, Content = "This is my first Post related to Entity Model", Title = "Transaction in EF 6 beta" }; context.Post_Details.Add(NewPost); context.SaveChanges(); PostAdditionalInformation PostInformation = new PostAdditionalInformation() { PostId = (101), PostName = "Working With Transaction in Entity Model 6 Beta Version" }; context.PostAddtional_Details.Add(PostInformation); context.SaveChanges(); dbcxtransaction.Commit(); } catch { dbcxtransaction.Rollback(); } } }

¿La reversión es realmente necesaria cuando las cosas van de lado? Tengo curiosidad porque la descripción de Commit dice: "Confirma la transacción subyacente de la tienda".

Mientras que la descripción de la reversión dice: "Revierte la transacción de la tienda subyacente".

Esto me da curiosidad, porque me parece que si no se llama a Commit, los comandos ejecutados previamente no se almacenarán (lo cual me parece lógico). Pero si ese es el caso, ¿cuál sería el motivo para llamar a la función Rollback? En EF5 utilicé TransactionScope que no tenía una función Rollback (solo una completa) que me pareció lógica. Debido a las razones del DTC de MS, ya no puedo usar TransactionScope, pero tampoco puedo usar un try catch como el ejemplo anterior (es decir, solo necesito el Commit).


  1. Dado que ha escrito un bloque ''using'' para crear una instancia de la transacción, no necesita mencionar explícitamente la función Rollback, ya que se retrotraerá automáticamente (a menos que se haya confirmado) en el momento de su eliminación.
  2. Pero si crea una instancia sin un bloque de uso, en ese caso es esencial deshacer la transacción en caso de una excepción (precisamente en un bloque catch) y eso también con una verificación nula para un código más robusto. El funcionamiento de BeginTransaction es diferente del alcance de la transacción (que solo necesita una función completa si todas las operaciones se completaron con éxito). En cambio, es similar al funcionamiento de las transacciones Sql.

No necesita llamar Rollback manualmente porque está usando la instrucción using .

DbContextTransaction.Dispose método DbContextTransaction.Dispose al final del bloque de using . Y se retrotraerá automáticamente la transacción si la transacción no se confirma correctamente (no se invocaron ni se encontraron excepciones). A continuación se muestra el código fuente del método SqlInternalTransaction.Dispose ( DbContextTransaction.Dispose finalmente lo delegará al usar el proveedor SqlServer):

private void Dispose(bool disposing) { // ... if (disposing && this._innerConnection != null) { this._disposing = true; this.Rollback(); } }

Verá, comprueba si _innerConnection no es nulo, si no, retrotrae la transacción (si se confirma, _innerConnection será nulo). Veamos qué hace Commit :

internal void Commit() { // Ignore many details here... this._innerConnection.ExecuteTransaction(...); if (!this.IsZombied && !this._innerConnection.IsYukonOrNewer) { // Zombie() method will set _innerConnection to null this.Zombie(); } else { this.ZombieParent(); } // Ignore many details here... } internal void Zombie() { this.ZombieParent(); SqlInternalConnection innerConnection = this._innerConnection; // Set the _innerConnection to null this._innerConnection = null; if (innerConnection != null) { innerConnection.DisconnectTransaction(this); } }


Siempre que siempre utilice SQL Server con EF, no es necesario usar explícitamente el catch para llamar al método Rollback. Permitir que el bloque que usa se revierte automáticamente en cualquier excepción siempre funcionará.

Sin embargo, cuando lo piensas desde el punto de vista del Entity Framework, puedes ver por qué todos los ejemplos usan la llamada explícita para deshacer la transacción. Para el EF, el proveedor de la base de datos es arbitrario y conectable y el proveedor puede ser reemplazado por MySQL o cualquier otra base de datos que tenga una implementación de proveedor de EF. Por lo tanto, desde el punto de vista de EF, no hay garantía de que el proveedor restituya automáticamente la transacción dispuesta, porque EF no conoce la implementación del proveedor de la base de datos.

Por lo tanto, como una práctica recomendada, la documentación de EF recomienda que se retrotraiga explícitamente, en caso de que algún día cambie los proveedores a una implementación que no se autodestruya al deshacerse.

En mi opinión, cualquier proveedor bueno y bien escrito revertirá automáticamente la transacción en el desecho, por lo que el esfuerzo adicional para envolver todo dentro del bloque de uso con un try-catch-rollback es excesivo.