Utiliser des transactions ou SaveChanges (false) et AcceptAllChanges ()?

J’ai étudié des transactions et il semble qu’ils prennent soin d’eux-mêmes dans EF tant que je transmets la valeur false à SaveChanges() et que j’appelle AcceptAllChanges() s’il n’y a pas d’erreurs:

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

Et si quelque chose ne va pas? est-ce que je ne dois pas revenir en arrière ou, dès que ma méthode est hors de scope, la transaction est-elle terminée?

Qu’advient-il des colonnes d’individus affectées à mi-parcours de la transaction? Je présume que si quelqu’un d’autre a ajouté un enregistrement après le mien avant que le mien ne se dégrade, cela signifie qu’il y aura une valeur d’identité manquante.

Y a-t-il une raison d’utiliser la classe TransactionScope standard dans mon code?

    Avec Entity Framework, la plupart du temps, SaveChanges() est suffisant. Cela crée une transaction ou s’inscrit dans toute transaction ambiante et effectue tout le travail nécessaire dans cette transaction.

    Parfois, le SaveChanges(false) + AcceptAllChanges() est utile.

    L’endroit le plus utile est celui où vous souhaitez effectuer une transaction dissortingbuée sur deux contextes différents.

    Ie quelque chose comme ça (mauvais):

     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() réussit mais que context2.SaveChanges() échoue, la transaction dissortingbuée entière est abandonnée. Mais malheureusement, Entity Framework a déjà ignoré les modifications sur context1 , de sorte que vous ne pouvez pas relire ou enregistrer efficacement la panne.

    Mais si vous changez votre code pour ressembler à ceci:

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

    Alors que l’appel à SaveChanges(false) envoie les commandes nécessaires à la firebase database, le contexte lui-même n’est pas modifié, vous pouvez donc le refaire si nécessaire ou vous pouvez interroger ObjectStateManager si vous le souhaitez.

    Cela signifie que si la transaction génère en réalité une exception, vous pouvez compenser, en ré-essayant ou en consignant l’état de chaque contexte ObjectStateManager quelque part.

    Voir mon blog pour en savoir plus.

    Si vous utilisez EF6 (Entity Framework 6+), cela a changé pour les appels à la firebase database SQL.
    Voir: http://msdn.microsoft.com/en-us/data/dn456843.aspx

    utilisez context.Database.BeginTransaction.

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

    Parce que certaines bases de données peuvent lancer une exception à dbContextTransaction.Commit (), alors mieux vaut:

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