我一直在调查交易,只要我将 false
传递给 SaveChanges()
,然后在没有错误的情况下调用 AcceptAllChanges()
,看起来他们会在EF中照顾自己:
SaveChanges(false);
// ...
AcceptAllChanges();
如果事情变坏怎么办?我不必回滚,或者一旦我的方法超出范围,交易结束了吗?
在事务中途分配的任何indentiy列会发生什么?我认为如果其他人在我的事情发生之前添加了一条记录,那么这意味着将会缺少一个身份值 .
有没有理由在我的代码中使用标准 TransactionScope
类?
3 回答
使用实体框架大部分时间
SaveChanges()
就足够了 . 这会创建一个事务,或在任何环境事务中登记,并在该事务中完成所有必要的工作 .有时虽然
SaveChanges(false) + AcceptAllChanges()
配对很有用 .对此最有用的地方是您希望跨两个不同的上下文执行分布式事务 .
即像这样(坏):
如果
context1.SaveChanges()
成功但context2.SaveChanges()
失败,则中止整个分布式事务 . 但不幸的是,实体框架已经放弃了context1
上的更改,因此您无法重播或有效地记录失败 .但是,如果您将代码更改为如下所示:
当对
SaveChanges(false)
的调用将必要的命令发送到数据库时,上下文本身不会更改,因此您可以在必要时再次执行此操作,或者您可以根据需要查询ObjectStateManager
.这意味着如果事务实际抛出异常,您可以通过在某处重新尝试或记录每个上下文的状态来进行补偿 .
有关更多信息,请参见my blog post .
如果您使用的是EF6(实体框架6),那么对于SQL的数据库调用,这已经发生了变化 .
见:http://msdn.microsoft.com/en-us/data/dn456843.aspx
使用context.Database.BeginTransaction .
来自MSDN:
var query = context.Posts.Where(p => p.Blog.Rating> = 5);
foreach(查询中的var post)
context.SaveChanges();
dbContextTransaction.Commit();
}
catch(例外)
{
dbContextTransaction.Rollback(); //根据MSDN文章要求
扔; //不在MSDN文章中,但建议如此异常仍然存在
}
}
}
因为某些数据库可以在dbContextTransaction.Commit()中抛出异常,所以更好: