З Entity Framework більшість часу SaveChanges()
достатньо. Це створює транзакцію або залучає до будь-якої навколишньої транзакції і виконує всю необхідну роботу в цій транзакції.
Іноді, хоча SaveChanges(false) + AcceptAllChanges()
спарювання корисне.
Найбільш корисне місце для цього - у ситуаціях, коли ви хочете зробити розподілену транзакцію в двох різних контекстах.
Тобто щось подібне (погано):
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();
}
Якщо це context1.SaveChanges()
вдалося, але context2.SaveChanges()
не вдалося, вся розподілена транзакція припиняється. Але, на жаль, Entity Framework вже відмовився від змін context1
, тому ви не можете відтворити або ефективно зареєструвати помилку.
Але якщо ви змінили код, щоб він виглядав так:
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)
надсилає необхідні команди в базу даних, сам контекст не змінюється, тому ви можете зробити це ще раз, якщо потрібно, або можете допитати, ObjectStateManager
якщо хочете.
Це означає, що якщо транзакція насправді викидає виняток, який ви можете компенсувати, повторно пробуючи або записуючи стан кожного контексту ObjectStateManager
десь.
Докладніше див. У моєму блозі .
SaveChanges(fase); ... AcceptAllChanges();
в першу чергу був візерунок. Зауважте, як прийнята відповідь на вищезазначене запитання написана автором блогу - і на який блог посилається інше питання. Все це поєднується.