Utilizzando Transactions o SaveChanges (false) e AcceptAllChanges ()?

Ho indagato sulle transazioni e sembra che si prendano cura di sé in EF fintanto che passo false a SaveChanges() e poi chiami AcceptAllChanges() se non ci sono errori:

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

Cosa succede se qualcosa va male? non devo eseguire il rollback o, non appena il mio metodo esce dal campo di applicazione, la transazione è terminata?

Cosa succede a tutte le colonne Indentiy che sono state assegnate a metà della transazione? Presumo che qualcun altro abbia aggiunto un disco dopo il mio prima che il mio sia andato a male, questo significa che ci sarà un valore di Identity framework mancante.

C’è qualche ragione per usare la class TransactionScope standard nel mio codice?

Con Entity Framework la maggior parte delle volte è sufficiente SaveChanges() . Ciò crea una transazione o si arresta in qualsiasi transazione ambientale e fa tutto il lavoro necessario in quella transazione.

A volte è utile l’associazione SaveChanges(false) + AcceptAllChanges() .

Il posto più utile per questo è nelle situazioni in cui si desidera eseguire una transazione distribuita attraverso due contesti diversi.

Cioè qualcosa del genere (male):

 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(); } 

Se context1.SaveChanges() positivo ma context2.SaveChanges() non riesce, l’intera transazione distribuita viene interrotta. Ma sfortunatamente Entity Framework ha già scartato le modifiche su context1 , quindi non è ansible riprodurre o registrare efficacemente l’errore.

Ma se cambi il tuo codice per assomigliare a questo:

 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(); } 

Mentre la chiamata a SaveChanges(false) invia i comandi necessari al database, il contesto stesso non viene modificato, quindi puoi farlo di nuovo se necessario, oppure puoi interrogare ObjectStateManager se lo desideri.

Ciò significa che se la transazione genera effettivamente un’eccezione che è ansible compensare, ri-tentando o registrando lo stato di ciascun contesto ObjectStateManager da qualche parte.

Vedi il mio post sul blog per ulteriori informazioni.

Se si utilizza EF6 (Entity Framework 6+), questo è cambiato per le chiamate al database in SQL.
Vedi: http://msdn.microsoft.com/en-us/data/dn456843.aspx

usa context.Database.BeginTransaction.

Da 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 } } } 

Perché alcuni database possono generare un’eccezione su dbContextTransaction.Commit (), quindi meglio questo:

 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(); } } }