Frage

Ich habe untersucht worden Transaktionen und es scheint, dass sie sich selbst in EF kümmern, solange ich false passieren SaveChanges() und rufen AcceptAllChanges() dann, wenn es keine Fehler sind:

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

Was ist, wenn etwas schlecht geht? nicht muss ich oder Rollback, sobald meine Methode den Gültigkeitsbereich verlässt, ist die Transaktion beendet?

Was passiert mit irgendwelchen indentiy Spalten, die auf halbem Weg durch die Transaktion zugewiesen wurden? Ich nehme an, wenn jemand anders einen Rekord nach meinem hinzugefügt, bevor Mine schlecht ging dann das bedeutet, es wird eine fehlende Identität Wert sein.

Gibt es einen Grund, den Standard TransactionScope Klasse in meinem Code zu benutzen?

War es hilfreich?

Lösung

Mit dem Entity Framework die meiste Zeit SaveChanges() ausreichend. Dies schafft eine Transaktion oder anwirbt in jeder Ambient-Transaktion und macht alle, die notwendigen Arbeiten in dieser Transaktion.

Manchmal aber die SaveChanges(false) + AcceptAllChanges() Paarung nützlich ist.

Der nützlichste Ort dafür ist, in Situationen, in denen Sie eine verteilte Transaktion über zwei verschiedene Kontexte tun wollen.

d. so etwas wie diese (sehr schlecht):

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

Wenn context1.SaveChanges() gelingt aber context2.SaveChanges() nicht die gesamte verteilte Transaktion abgebrochen. Aber leider hat das Entity Framework verworfen bereits die Änderungen auf context1, so kann man nicht wiederholen oder effektiv die Fehler protokolliert.

Aber wenn Sie Ihren Code ändern wie folgt aussehen:

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

}

Während der Aufruf an SaveChanges(false) die notwendigen Befehle an die Datenbank sendet, sich der Kontext nicht geändert wird, so dass Sie es wieder tun können, wenn nötig, oder Sie können die ObjectStateManager abfragen, wenn Sie wollen.

Das bedeutet, wenn die Transaktion tatsächlich eine Ausnahme auslöst können Sie, entweder durch erneutes versuchen oder Protokollierung Zustand jeder Kontexte kompensieren ObjectStateManager irgendwo.

Siehe meine Blog-Post für mehr.

Andere Tipps

Wenn Sie mit EF6 (Entity Framework 6+), hat sich dies geändert für Datenbank SQL-Aufrufe.
Siehe: http://msdn.microsoft.com/en-us/data/dn456843.aspx

context.Database.BeginTransaction verwenden.

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

Da einige Datenbank kann eine Ausnahme bei dbContextTransaction.Commit werfen () so besser dies:

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(); 
    } 
  } 
} 
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top