我一直在调查事务,只要我将false
传递给SaveChanges()
而后若是没有错误就调用AcceptAllChanges()
,它们彷佛会在EF中处理它们本身: 数据库
SaveChanges(false); // ... AcceptAllChanges();
若是事情变坏怎么办? 我没必要回滚,或者一旦个人方法超出范围,交易结束了吗? 框架
在事务中途分配的任何indentiy列会发生什么? 我认为若是其余人在个人事情发生以前添加了一条记录,那么这意味着会有一个缺失的身份值。 分布式
有没有理由在个人代码中使用标准的TransactionScope
类? post
若是您使用的是EF6(实体框架6+),则对数据库调用SQL的状况已发生变化。
请参阅: http : //msdn.microsoft.com/en-us/data/dn456843.aspx ui
使用context.Database.BeginTransaction。 spa
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()中抛出异常,因此更好: code
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(); } } }
使用Entity Framework大部分时间SaveChanges()
就足够了。 这会建立一个事务,或在任何环境事务中登记,并在该事务中完成全部必要的工做。 blog
有时虽然SaveChanges(false) + AcceptAllChanges()
配对颇有用。 事务
对此最有用的地方是您但愿跨两个不一样的上下文执行分布式事务。 get
就是这样(坏):
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
状态来进行补偿。