我一直在調查事務,只要我將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
狀態來進行補償。