我一直在调查事务,似乎只要我将false
传递给SaveChanges()
,然后在没有错误的情况下调用AcceptAllChanges()
,它们就会在EF中自行处理:
SaveChanges(false);
// ...
AcceptAllChanges();
如果事情变坏了怎么办?我不需要回滚吗?或者,一旦我的方法超出作用域,事务就结束了吗?
事务中途分配的任何缩进列会发生什么情况?我假设如果其他人在我的记录之后添加了记录,而我的记录还没有坏,那么这意味着将会有一个丢失的标识值。
有什么理由在我的代码中使用标准的TransactionScope
类吗?
发布于 2009-05-02 21:24:26
对于实体框架,大多数情况下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
的状态来进行补偿。
发布于 2015-03-06 10:19:32
因为某些数据库可能会在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();
}
}
}
https://stackoverflow.com/questions/815586
复制相似问题