Использование транзакций или SaveChanges (false) и AcceptAllChanges ()?
я расследовал транзакции, и похоже, что они заботятся о себе в EF, пока я прохожу false
to SaveChanges()
и затем вызов AcceptAllChanges()
если нет ошибок:
SaveChanges(false);
// ...
AcceptAllChanges();
что, если что-то пойдет не так? разве мне не нужно откатывать или, как только мой метод выходит за рамки, транзакция завершена?
что происходит с любыми столбцами indentiy, которые были назначены на полпути через транзакцию? Я предполагаю, что если кто-то добавил запись после мой раньше меня пошел плохо это означает отсутствующее значение личности.
есть ли причина использовать стандарт TransactionScope
класс в моем коде?
3 ответов
С 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
куда-то.
Если вы используете EF6 (Entity Framework 6+), это изменилось для вызовов базы данных SQL.
Смотри:http://msdn.microsoft.com/en-us/data/dn456843.aspx
использовать контекст.База данных.BeginTransaction.
из 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 } } }
потому что некоторая база данных может выдать исключение в dbContextTransaction.Commit () так лучше это:
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();
}
}
}