İşlemler veya SaveChanges (false) ve AcceptAllChanges () kullanılıyor mu?


346

Ben işlemlerini soruşturma yürüttükleri ve bunların uzun zaman geçmesi gibi EF kendilerine özen anlaşılmaktadır falseiçin SaveChanges()ve daha sonra çağrı AcceptAllChanges()hata varsa:

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

Ya bir şeyler kötüleşirse? geri almam gerekmez mi yoksa yöntemim kapsam dışına çıkar çıkmaz işlem sona erer mi?

İşlemin yarısına atanmış herhangi bir girinti sütununa ne olur? Sanırım başka birinin benimki kötüye gitmeden önce bir rekor ekleyip eklemediğini varsayarsak, bu, kimlik değerinin eksik olacağı anlamına gelir.

Kodumda standart TransactionScopesınıfı kullanmak için herhangi bir neden var mı ?


1
BuSaveChanges(fase); ... AcceptAllChanges(); , ilk etapta neden bir model olduğunu anlamama yardımcı oldu . Yukarıdaki soruya kabul edilen cevabın, bir blog yazarı tarafından nasıl yazıldığına ve bu blogun diğer soruya nasıl atıfta bulunduğuna dikkat edin. Her şey bir araya geliyor.
Kızıl Bezelye

Yanıtlar:


451

Varlık Çerçevesi ile çoğu zaman SaveChanges()yeterlidir. Bu bir işlem oluşturur veya herhangi bir ortam işlemine kaydolur ve bu işlemde gerekli tüm işleri yapar.

Bazen SaveChanges(false) + AcceptAllChanges()eşleştirme faydalı olsa da .

Bunun için en kullanışlı yer, iki farklı bağlamda dağıtılmış bir işlem yapmak istediğiniz durumlardır.

Yani böyle bir şey (kötü):

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

Eğer context1.SaveChanges()başarılı ama context2.SaveChanges()bütün dağıtılmış işlem iptal edilir başarısız olur. Ancak ne yazık ki Entity Framework değişiklikleri zaten attı context1, bu nedenle hatayı tekrar oynatamaz veya etkili bir şekilde kaydedemezsiniz.

Ancak kodunuzu şöyle görünecek şekilde değiştirirseniz:

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

}

SaveChanges(false)Veritabanına gerekli komutları gönderme çağrısı yapılırken, bağlamın kendisi değişmez, böylece gerekirse yeniden yapabilir veya isterseniz sorgulayabilirsiniz ObjectStateManager.

Bu, işlemin gerçekten bir istisna atarsa, her bağlamın durumunu yeniden denemek veya günlüğe kaydederek telafi edebileceğiniz anlamına gelir ObjectStateManager.

Bkz benim blog yazısı daha fazlası.


3
Bu harika, teşekkürler ... Yani bir şey başarısız olursa geri almak zorunda değilim ?? SaveChanges, kaydedildiği için işaretler, ama aslında kabulet değişimleri yapana kadar taahhüt yok .. ama bir şeyler ters giderse .. i geri almak gerekecek böylece benim nesne doğru durumuna döner mi?
mark smith

33
@Mark: "geri alma" ile ifade ediyorsanız, nesnelerinizi veritabanında oldukları duruma geri döndürün, o zaman hayır, bunu yapmak istemezsiniz, çünkü kullanıcının nesnelerdeki tüm değişikliklerini kaybedersiniz . SaveChanges(false)veritabanına gerçek güncellemeyi yapar, AcceptAllChanges()EF'ye "Tamam, hangi şeylerin kaydedilmesi gerektiğini unutabilirsiniz, çünkü bunlar başarıyla kaydedilmiştir." Eğer SaveChanges(false)başarısız AcceptAllChanges()denilen asla ve EF hala değiştirildi ve ihtiyaç tekrar veritabanına kaydedilmesine özelliklere sahip olarak nesneyi dikkate alacaktır.
BlueRaja - Danny Pflughoeft

Önce Kod'u kullanarak bunu nasıl yapacağınızı önerebilir misiniz? SaveChanges veya AcceptAllChanges yöntemine yönelik bir parametre yok
Kirsten Greed

2
Ben Kod Birinci ile bu tekniği kullanarak ilgili bir soru sordum burada
Kirsten Greed

13
Bu, EF 6.1'de artık mümkün değildir. Şimdi çalışmak için ne tür ayarlamalar yapılması gerektiğini biliyor musunuz?
Alex Dresko

113

EF6 (Entity Framework 6+) kullanıyorsanız, bu SQL'e veritabanı çağrıları için değişmiştir.
Bkz. Http://msdn.microsoft.com/en-us/data/dn456843.aspx

context.Database.BeginTransaction öğesini kullanın.

MSDN'den:

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

52
İşlemde "kullanarak" kullandığınızda, geri alma ile try-catch gerekmez.
Robert

12
Böyle bir istisnayı yakalamak için bir istisna alıyorum. Veritabanı işleminin sessizce başarısız olmasına neden olur. SO'nun doğası gereği, birisi bu örneği alıp bir üretim uygulamasında kullanabilir.
B2K

3
@ B2K: İyi bir nokta, ancak bu kod bağlantılı Microsoft makalesinden kopyalandı . Ben kimsenin kullandığı umut onların :) üretimde kod
J Bryan Fiyat

6
@Robert MSDN makalesine göre Geri Alma () gereklidir. TransactionScope örneği için bir Rollback komutunu bilerek bırakırlar. @ B2K throw;MSDN snippet'ine ekledim ve bunun MSDN makalesindeki orijinal olmadığını açıkça belirttim.
Todd

6
(Doğru ise) Bu, işleri temizleyebilir: EF + MSSQL gibi seslerin Geri Almaya ihtiyacı yoktur, ancak EF + diğer SQL sağlayıcıları gerekebilir. EF'in hangi veritabanından bahsettiği konusunda agnostik olması gerektiğinden, Rollback()MySql veya bu otomatik davranışı olmayan bir şeyle konuşması durumunda çağrılır.
Jared

-5

Bazı veritabanı dbContextTransaction.Commit () bir istisna atabilir, çünkü bu çok daha iyi:

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

7
Böyle bir istisnayı yakalamak için bir istisna alıyorum. Veritabanı işleminin sessizce başarısız olmasına neden olur. SO'nun doğası gereği, birisi bu örneği alıp bir üretim uygulamasında kullanabilir.
B2K

6
Bu aslında alıntıladığı MSDN sayfasına atıfta bulunan diğer cevapla aynı değil mi? Gördüğüm tek fark geçmek olduğunu içine ve ayrıca çağrı . falsecontext.SaveChanges();context.AcceptAllChanges();
Wai Ha Lee

@ B2K geri alma gerekli değildir - işlem çalışmazsa hiçbir şey yapılmaz. Ayrıca Rollback'e yapılan açık çağrı başarısız olabilir - cevabımı buradan görebilirsiniz stackoverflow.com/questions/41385740/…
Ken

Geri alma, itiraz ettiğim şey değil. Bu cevabın yazarı, istisnayı yeniden değerlendirmek için kodlarını güncelledi ve böylece itiraz ettiğim şeyi çözdü.
B2K

Üzgünüm, telefonumdan yorum yaptım. Todd istisnayı yeniden atar, eMeL yapmaz. Yakalamada, geliştiriciyi veya kullanıcıyı geri dönüşe neden olan bir sorunla ilgili bilgilendiren bir şey olmalıdır. Bu, bir günlük dosyasına yazmak, istisnayı geri yüklemek veya kullanıcıya bir mesaj döndürmek olabilir.
B2K
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.