數據訪問層之UnitOfWork

本章我們繼續IUnitOfWork的開發,從之前的IRepository接口中就可以看出,我們並沒有處理單元事務,
數據CUD每次都是立即執行的,這樣有一些不好的地方,比如數據訪問次數會增多,一筆數據的完整性無法保證
比如:批量新增2條記錄,只有一條成功,這樣的情況就應該Rollback;可能有人已經想到用數據庫自帶的事務保證完整性
雖然是可以,但是這樣就不可避免地在業務層耦合SqlTransaction,我不想這種情況出現;
所以我們用windows自帶的分布式事務TransactionScope來實現,TransactionScope可以實現多個數據庫的事務鎖,這點就比SqlTransaction強一些
當然我了解到分布式事務是不一般的復雜的,那些更好的處理方式我還沒有掌握,所以先這么寫吧,有這方面經驗的朋友歡迎提建議
IUnitOfWork.cs
1 public interface IUnitOfWork<T> where T : class
2 {
3 void RegisterAdd(T entity, Action callback);
4 void RegisterUpdate(T entity, Action callback);
5 void RegisterDelete(T entity, Action callback);
6 void Commit();
7 }
注冊新增操作:RegisterAdd
注冊更新操作:RegisterUpdate
注冊修改操作:RegisterDelete
提交數據:Commit
工作單元的實現
1 public class UnitOfWork<T> : IUnitOfWork<T> where T : class
2 {
3 private Dictionary<T, Action> addEntities;
4 private Dictionary<T, Action> updateEntities;
5 private Dictionary<T, Action> deleteEntities;
6
7 public UnitOfWork()
8 {
9 addEntities = new Dictionary<T, Action>();
10 updateEntities = new Dictionary<T, Action>();
11 deleteEntities = new Dictionary<T, Action>();
12 }
13
14 public void RegisterAdd(T entity, Action callback)
15 {
16 this.addEntities.Add(entity, callback);
17 }
18
19 public void RegisterUpdate(T entity, Action callback)
20 {
21 this.updateEntities.Add(entity, callback);
22 }
23
24 public void RegisterDelete(T entity, Action callback)
25 {
26 this.deleteEntities.Add(entity, callback);
27 }
28
29 public void Commit()
30 {
31 using (TransactionScope scope = new TransactionScope())
32 {
33 foreach (var entity in deleteEntities.Keys)
34 {
35 this.deleteEntities[entity]();
36 }
37
38 foreach (var entity in updateEntities.Keys)
39 {
40 this.updateEntities[entity]();
41 }
42
43 foreach (var entity in addEntities.Keys)
44 {
45 this.addEntities[entity]();
46 }
47
48 scope.Complete();
49 }
50 }
51 }
這里我們用了Action,這個是無返回值委托方法,如果大家需要返回值可以用Func
實現我們還是用DapperRepository,修改一下。在新增方法中注冊數據持久化方法

好了,現在我們來看看測試結果
測試工作單元

還是用原來那個DapperRepositoryTest
我們修改一下實現過程:
單個新增

批量新增

運行結果

我們把表結構改一下,名稱改成不能為null

AddBatch也要修改,正常的執行結果一個是拋出異常
1 [TestMethod]
2 public void AddBatch()
3 {
4 try
5 {
6 var loginUser1 = new LoginUser()
7 {
8 Id = Guid.NewGuid(),
9 LoginName = "lanxiaoke-" + Guid.NewGuid().ToString(),
10 Password = "mima1987",
11 IsEnabled = 1,
12 CreateTime = DateTime.Now
13 };
14
15 var loginUser2 = new LoginUser()
16 {
17 Id = Guid.NewGuid(),
18 //LoginName = "lanxiaoke-" + Guid.NewGuid().ToString(),
19 Password = "mima1987",
20 IsEnabled = 1,
21 CreateTime = DateTime.Now
22 };
23
24 var list = new List<LoginUser>();
25 list.Add(loginUser1);
26 list.Add(loginUser2);
27
28 repository.AddBatch(list);
29 unitOfWork.Commit();
30 }
31 catch (Exception ex)
32 {
33 var err = ex.Message;
34 }
35
36 //long count = repository.Count(t => t.LoginName.In(new string[] { loginUser1.LoginName, loginUser2.LoginName }));
37
38 //Assert.AreEqual(true, count >0);
39 }
運行看看

如期運行,到這里,工作單元就講完了
完整項目架構
我們來看看完整的數據訪問層架構

整個數據訪問層就講完了,雖然有些簡陋,但是基本功能都有了
項目架構開發系列
- 項目架構開發:數據訪問層之Cache
- 項目架構開發:數據訪問層之Logger
- 項目架構開發:數據訪問層之Query
- 項目架構開發:數據訪問層之Repository
- 項目架構開發:數據訪問層之UnitOfWork

