前提條件
TransactionScope類需要引用System.Transactions;
數據庫環境及需求
現在假設有兩個表如圖:
表TA 表TB
現有數據:
現在的需求是:每往TA中插入一條數據,就更新TB的第一行,值為表TA的所有行的Age的平均值
可以看到表TB的Remark長度僅僅為2,待會利用這個制造錯誤
當不使用TransactionScope時:

using (EFTestEntities db = new EFTestEntities()) { //數據庫TA原有2行,此時添加第3行 var aEntity = new TA { Name = "a", Age = 20 }; db.TA.Add(aEntity); var listTA = db.TA.ToList();//此時list只有2行,新添加的沒有讀取到 int totalAge = 0; listTA.ForEach(p => totalAge += p.Age); //獲取表TB的第一行,並修改AvgAge值 var bEntity = db.TB.First(); bEntity.AvgAge = totalAge / listTA.Count; bEntity.Remark = "bb"; db.SaveChanges(); //結果是Tb的值沒有變化 }
你認為是添加TA后沒有db.SaveChanges();? 的確,添加這個之后,可以讀取到新添加的值了,但是沒有事務了,如:

using (EFTestEntities db = new EFTestEntities()) { //數據庫TA原有2行,此時添加第3行 var aEntity = new TA { Name = "a", Age = 20 }; db.TA.Add(aEntity); db.SaveChanges(); var listTA = db.TA.ToList();//此時list有3行了,新添加的可以被讀取到 int totalAge = 0; listTA.ForEach(p => totalAge += p.Age); //獲取表TB的第一行,並修改AvgAge值 var bEntity = db.TB.First(); bEntity.AvgAge = totalAge / listTA.Count; bEntity.Remark = "bbc";//故意超出長度,制造錯誤 db.SaveChanges(); //結果是TA添加了新行,但是TB修改時出錯導致修改失敗。造成了數據不一致 }
結果是TA添加了新行,但是TB因為remark超出長度導致導致修改失敗,此時TB的數據是錯的。
怎樣可以避免這個問題?答案就是用事務。
使用TransactionScope:

using (EFTestEntities db = new EFTestEntities()) { using (TransactionScope ts = new TransactionScope()) { //數據庫TA原有2行,此時添加第3行 var aEntity = new TA { Name = "a", Age = 20 }; db.TA.Add(aEntity); db.SaveChanges();//重點,必須要db.SaveChanges(),然后下面才能獲取到新添加的行 var listTA = db.TA.ToList();//此時list有3行了,新添加的可以被讀取到 int totalAge = 0; listTA.ForEach(p => totalAge += p.Age); //獲取表TB的第一行,並修改AvgAge值 var bEntity = db.TB.First(); bEntity.AvgAge = totalAge / listTA.Count; bEntity.Remark = "bbc";//故意超出長度,制造錯誤 db.SaveChanges(); //執行到此處程序報錯 ts.Complete();//事務提交未執行 //結果是自動回滾,相當於此次沒有對數據庫做任何操作。保持了數據一致性 } }
下面給出正確的示例,實現以上需求:

using (EFTestEntities db = new EFTestEntities()) { using (TransactionScope ts = new TransactionScope()) { //數據庫TA原有2行,此時添加第3行 var aEntity = new TA { Name = "a", Age = 20 }; db.TA.Add(aEntity); db.SaveChanges();//重點,必須要db.SaveChanges(),然后下面才能獲取到新添加的行 var listTA = db.TA.ToList();//此時list有3行了,新添加的可以被讀取到 int totalAge = 0; listTA.ForEach(p => totalAge += p.Age); //獲取表TB的第一行,並修改AvgAge值 var bEntity = db.TB.First(); bEntity.AvgAge = totalAge / listTA.Count; bEntity.Remark = "bb";//數據符合規范 db.SaveChanges(); //保存 ts.Complete();//提交事務 //結果是執行成功,TA多一條數據,同時TB的值也變了 } }
一切都nice了!