Dzięki Entity Framework większość czasu SaveChanges()
jest wystarczająca. To tworzy transakcję lub powiększa się w dowolnej transakcji otoczenia i wykonuje wszystkie niezbędne prace w tej transakcji.
Czasami SaveChanges(false) + AcceptAllChanges()
parowanie jest przydatne.
Najbardziej użytecznym miejscem do tego są sytuacje, w których chcesz dokonać transakcji rozproszonej w dwóch różnych kontekstach.
Tzn. Coś takiego (źle):
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();
}
Jeśli się context1.SaveChanges()
powiedzie, ale się context2.SaveChanges()
nie powiedzie, cała rozproszona transakcja zostanie przerwana. Ale niestety Entity Framework już odrzucił zmiany context1
, więc nie można odtwarzać ani skutecznie rejestrować awarii.
Ale jeśli zmienisz kod, aby wyglądał tak:
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();
}
Podczas gdy wezwanie do SaveChanges(false)
wysłania niezbędnych poleceń do bazy danych, sam kontekst nie ulega zmianie, więc możesz to zrobić ponownie, jeśli to konieczne, lub możesz przesłuchać, ObjectStateManager
jeśli chcesz.
Oznacza to, że jeśli transakcja faktycznie zgłasza wyjątek, który można zrekompensować, albo próbując ponownie, albo rejestrując stan każdego kontekstu ObjectStateManager
gdzieś.
Zobacz mój post na blogu, aby uzyskać więcej.
SaveChanges(fase); ... AcceptAllChanges();
był to wzorzec. Zwróć uwagę, w jaki sposób autor bloga napisał zaakceptowaną odpowiedź na powyższe pytanie - a do tego bloga odwołuje się drugie pytanie. Wszystko się łączy.