Answers:
使用实体框架,大多数时间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()
失败,则整个分布式事务中止。但是很遗憾,实体框架已经放弃了对的更改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(false)
确实对数据库进行了更新,同时AcceptAllChanges()
告诉EF:“好的,您可以忘记需要保存哪些内容,因为已成功保存了它们。” 如果SaveChanges(false)
失败,AcceptAllChanges()
将永远不会调用,并且EF仍将您的对象视为具有已更改的属性,需要将其保存回数据库。
如果您使用的是EF6(Entity Framework 6+),则对SQL的数据库调用已更改。
请参阅:http://msdn.microsoft.com/en-us/data/dn456843.aspx
使用context.Database.BeginTransaction。
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 } } }
throw;
到MSDN代码段中,并清楚地表明它不是MSDN文章中的原始内容。
Rollback()
在与MySql或没有自动行为的情况下被调用。
因为某些数据库可以在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();
}
}
}
SaveChanges(fase); ... AcceptAllChanges();
是一种模式。请注意如何接受的答案对上述问题,由笔者写博客 -这博客是在其他问题中引用。全部融合在一起。