我一直在调查事务,只要我将false
传递给SaveChanges()
然后如果没有错误就调用AcceptAllChanges()
,它们似乎会在EF中处理它们自己:
SaveChanges(false);
// ...
AcceptAllChanges();
如果事情变坏怎么办? 我不必回滚,或者一旦我的方法超出范围,交易结束了吗?
在事务中途分配的任何indentiy列会发生什么? 我认为如果其他人在我的事情发生之前添加了一条记录,那么这意味着会有一个缺失的身份值。
有没有理由在我的代码中使用标准的TransactionScope
类?
#1楼
如果您使用的是EF6(实体框架6+),则对数据库调用SQL的情况已发生变化。
请参阅: http : //msdn.microsoft.com/en-us/data/dn456843.aspx
使用context.Database.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 } } }
#2楼
因为某些数据库可以在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();
}
}
}
#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()
失败,则中止整个分布式事务。 但不幸的是,实体框架已经放弃了对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
状态来进行补偿。
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3188043