transaction transacciones framework c# entity-framework transactions

c# - transacciones - entity framework transaction



¿Usando Transactions o SaveChanges(false) y AcceptAllChanges()? (3)

He estado investigando transacciones y parece que se cuidan en EF siempre que pase false a SaveChanges() y luego llamen a AcceptAllChanges() si no hay errores:

SaveChanges(false); // ... AcceptAllChanges();

¿Y si algo va mal? ¿no tengo que revertir o, tan pronto como mi método sale del alcance, se termina la transacción?

¿Qué sucede con las columnas de referencia que se asignaron a mitad de la transacción? Supongo que si alguien más agregó un registro después del mío antes de que el mío se echara a perder, significa que faltará un valor de Identidad.

¿Hay alguna razón para usar la clase TransactionScope estándar en mi código?


Con el Entity Framework la mayor parte del tiempo, SaveChanges() es suficiente. Esto crea una transacción, o se enlista en cualquier transacción ambiental, y hace todo el trabajo necesario en esa transacción.

A veces, aunque el SaveChanges(false) + AcceptAllChanges() es útil.

El lugar más útil para esto es en situaciones en las que desea realizar una transacción distribuida en dos Contextos diferentes.

Es decir, algo como esto (mal):

using (TransactionScope scope = new TransactionScope()) { //Do something with context1 //Do something with context2 //Save and discard changes context1.SaveChanges(); //Save and discard changes context2.SaveChanges(); //if we get here things are looking good. scope.Complete(); }

Si context1.SaveChanges() tiene éxito pero context2.SaveChanges() falla, la transacción distribuida completa se cancela. Pero, desafortunadamente, el Entity Framework ya ha descartado los cambios en context1 , por lo que no puede reproducir o registrar efectivamente el error.

Pero si cambias tu código para que se vea así:

using (TransactionScope scope = new TransactionScope()) { //Do something with context1 //Do something with context2 //Save Changes but don''t discard yet context1.SaveChanges(false); //Save Changes but don''t discard yet context2.SaveChanges(false); //if we get here things are looking good. scope.Complete(); context1.AcceptAllChanges(); context2.AcceptAllChanges(); }

Si bien la llamada a SaveChanges(false) envía los comandos necesarios a la base de datos, el contexto en sí no se modifica, por lo que puede hacerlo de nuevo si es necesario, o puede interrogar al ObjectStateManager si lo desea.

Esto significa que si la transacción realmente genera una excepción que puede compensar, volviendo a intentar o registrando el estado de cada ObjectStateManager algún lugar.

Ver my blog para más.


Debido a que alguna base de datos puede lanzar una excepción en dbContextTransaction.Commit (), mejor esto:

using (var context = new BloggingContext()) { using (var dbContextTransaction = context.Database.BeginTransaction()) { try { context.Database.ExecuteSqlCommand( @"UPDATE Blogs SET Rating = 5" + " WHERE Name LIKE ''%Entity Framework%''" ); var query = context.Posts.Where(p => p.Blog.Rating >= 5); foreach (var post in query) { post.Title += "[Cool Blog]"; } context.SaveChanges(false); dbContextTransaction.Commit(); context.AcceptAllChanges(); } catch (Exception) { dbContextTransaction.Rollback(); } } }


Si está utilizando EF6 (Entity Framework 6+), esto ha cambiado para las llamadas de base de datos a SQL.
Consulte: http://msdn.microsoft.com/en-us/data/dn456843.aspx

utilizar context.Database.BeginTransaction.

Desde MSDN:

using (var context = new BloggingContext()) { using (var dbContextTransaction = context.Database.BeginTransaction()) { try { context.Database.ExecuteSqlCommand( @"UPDATE Blogs SET Rating = 5" + " WHERE Name LIKE ''%Entity Framework%''" ); var query = context.Posts.Where(p => p.Blog.Rating >= 5); foreach (var post in query) { post.Title += "[Cool Blog]"; } context.SaveChanges(); dbContextTransaction.Commit(); } catch (Exception) { dbContextTransaction.Rollback(); //Required according to MSDN article throw; //Not in MSDN article, but recommended so the exception still bubbles up } } }