使用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狀態來進行補償。

有關更多信息 ,請參閱個人 博文

相關文章
相關標籤/搜索