使用Transactions或SaveChanges(false)和AcceptAllChanges()?

我一直在调查事务,只要我将false传递给SaveChanges()而后若是没有错误就调用AcceptAllChanges() ,它们彷佛会在EF中处理它们本身: 数据库

SaveChanges(false);
// ...
AcceptAllChanges();

若是事情变坏怎么办? 我没必要回滚,或者一旦个人方法超出范围,交易结束了吗? 框架

在事务中途分配的任何indentiy列会发生什么? 我认为若是其余人在个人事情发生以前添加了一条记录,那么这意味着会有一个缺失的身份值。 分布式

有没有理由在个人代码中使用标准的TransactionScope类? post


#1楼

若是您使用的是EF6(实体框架6+),则对数据库调用SQL的状况已发生变化。
请参阅: http//msdn.microsoft.com/en-us/data/dn456843.aspx ui

使用context.Database.BeginTransaction。 spa

来自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()中抛出异常,因此更好: 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(); 
    } 
  } 
}

#3楼

使用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状态来进行补偿。

有关更多信息 ,请参阅个人 博文

相关文章
相关标签/搜索