掀起你的蓋頭來:Unit Of Work-工做單元

寫在前面

閱讀目錄:html

掀起了你的蓋頭來,讓我看你的眼睛,你的眼睛明又亮呀,好像那水波一模樣;掀起了你的蓋頭來,讓我看你的臉兒,看看你的臉兒紅又圓呀,好像那蘋果到秋天。。。安全

  Hi,Unit Of Work,掀起你的蓋頭來,原來 You are so beautiful !併發

概念中的理解

Unit Of Work:維護受業務事務影響的對象列表,並協調變化的寫入和併發問題的解決。即管理對象的CRUD操做,以及相應的事務與併發問題等。Unit of Work是用來解決領域模型存儲和變動工做,而這些數據層業務並不屬於領域模型自己具備的。ide

  關於Unit Of Work的更多詳情,請查看:http://martinfowler.com/eaaCatalog/unitOfWork.htmlUnit Of Work中的「Unit」是單元的意思,知道單元測試的朋友都知道其也包含「Unit」單詞,可是是一個意思嗎?Unit Test(單元測試)雖然也包含「Unit」這個單詞,可是意義並非同樣,單元測試中的「Unit」能夠看作是最小單元,好比組裝飛機的最小零部件,可是Unit Of Work(工做單元)並不是無此,注意後面「Work」單詞,意思是能夠「工做」的單元,好比一場籃球比賽須要兩個隊,10名上場球員參與,這樣完成的「動做」纔會稱之爲籃球比賽,也就是「工做單元」,一個籃球隊或是一個籃球隊員並不能完成稱爲籃球比賽,可是這個工做的"單元"也只是相對而言,好比上籃動做就只須要一個籃球隊員就能夠完成,那這個籃球隊員就能夠看作是「工做單元」。須要注意的是,Unit中能夠包含不少「動做」,能夠是一個也能夠是多個,好比上面的例子,若是「單元」中包含對於多個動做,那這個「單元」中全部的動做都是「內聚」的,脫離這個「單元」這個動做就沒有意義了,好比籃球比賽中的一次吹罰,固然這只是字面上理解的意思,也只是我我的的一些見解,但願看到着沒有被我忽悠到。單元測試

  扯了一些不沾邊的東西,咱們再看一個現實中例子,也最能說明Unit Of Work所包含的意思,就是銀行轉帳操做,包含兩個動做:轉出方扣錢和轉入方加錢,這兩個動做要麼都完成,要麼都不完成,也就是事務操做,完成就Commit(提交),完不成就Rollback(回滾)。學習

  回到Unit Of Work的定義,Unit of Work是用來解決領域模型存儲和變動工做,在ORM進行持久化的時候,好比Entity Framework的SaveChanges操做,其實就能夠看作是Unit Of Work,也就是定義中所說「用來解決領域模型存儲和變動工做」,可是若是項目是基於Entity Framework進行DDD(領域驅動設計)開發設計的,那Entity Framework中的Domain Model就必然包含業務邏輯,這就不符合「而這些數據層業務並不屬於領域模型自己具備的」,也就是說Unit Of Work必須獨立於Domain Layer(領域層),注意獨立的業務是「數據層」業務,並非業務場景中的「業務」,好比「轉帳業務」,轉出方扣錢和轉入方加錢這個業務就屬於「數據層業務」,有的人會把Unit Of Work放在Domain Layer(領域層)中,實際上是有些不恰當的,應該是放在Infrastructure Layer(基礎層)中,但其實也只是相對而言,若是涉及到具體的業務單元模塊,具體實現能夠放在領域層中。測試

  在DDD(領域驅動設計)開發設計中,Unit Of Work的使用通常會結合Repository(倉儲)使用,有關Repository能夠參閱dudu的一篇文章:http://www.cnblogs.com/dudu/archive/2011/05/25/repository_pattern.html,文中的解釋很清楚直白:ui

Repository:是一個獨立的層,介於領域層與數據映射層(數據訪問層)之間。它的存在讓領域層感受不到數據訪問層的存在,它提供一個相似集合的接口提供給領域層進行領域對象的訪問。Repository是倉庫管理員,領域層須要什麼東西只需告訴倉庫管理員,由倉庫管理員把東西拿給它,並不須要知道東西實際放在哪。spa

  Unit Of Work所作的工做能夠看作是收集Repository出入庫的「商品」,便於一次裝車,運輸過程當中若是沒有出現問題,那這車的全部「商品」就安全到達,若是出現問題,那這車的全部「商品」所有打回,這輛車就是「單元」的意思。.net

  關於Repository和Unit Of Work的關係,簡單畫了個示意圖:

                點擊查看大圖

代碼中的實現

  關於Unit Of Work項目中的應用,能夠參照dax.net的Byteart Retail項目,本人如今也正在學習中,項目是基於DDD設計實現的,下面是IUnitOfWork的示例代碼:

 1 namespace ByteartRetail.Domain
 2 {
 3     /// <summary>
 4     /// 表示全部集成於該接口的類型都是Unit Of Work的一種實現。
 5     /// </summary>
 6     /// <remarks>有關Unit Of Work的詳細信息,請參見UnitOfWork模式:http://martinfowler.com/eaaCatalog/unitOfWork.html 7     /// </remarks>
 8     public interface IUnitOfWork
 9     {
10         /// <summary>
11         /// 得到一個<see cref="System.Boolean"/>值,該值表述了當前的Unit Of Work事務是否已被提交。
12         /// </summary>
13         bool Committed { get; }
14         /// <summary>
15         /// 提交當前的Unit Of Work事務。
16         /// </summary>
17         void Commit();
18         /// <summary>
19         /// 回滾當前的Unit Of Work事務。
20         /// </summary>
21         void Rollback();
22     }
23 }

  根據UnitOfWork中的概念描述「這些數據層業務並不屬於領域模型自己具備的」,因此IUnitOfWork放在Infrastructure Layer(基礎設施層),其實IUnitOfWork的具體管理實現是放在領域層的,但不會放在Domain Model(領域模型)中,具體的數據層業務會結合Repository,也就是說IUnitOfWork會貫徹全部的Repository實現,由於它要對全部倉儲的的持久化作統一管理:

 1     /// <summary>
 2     /// Represents that the implemented classes are repository contexts.
 3     /// </summary>
 4     public interface IRepositoryContext : IUnitOfWork, IDisposable
 5     {
 6         /// <summary>
 7         /// Gets the unique-identifier of the repository context.
 8         /// </summary>
 9         Guid ID { get; }
10         /// <summary>
11         /// Registers a new object to the repository context.
12         /// </summary>
13         /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
14         /// <param name="obj">The object to be registered.</param>
15         void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
16             where TAggregateRoot : class, IAggregateRoot;
17         /// <summary>
18         /// Registers a modified object to the repository context.
19         /// </summary>
20         /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
21         /// <param name="obj">The object to be registered.</param>
22         void RegisterModified<TAggregateRoot>(TAggregateRoot obj)
23             where TAggregateRoot : class, IAggregateRoot;
24         /// <summary>
25         /// Registers a deleted object to the repository context.
26         /// </summary>
27         /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
28         /// <param name="obj">The object to be registered.</param>
29         void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
30             where TAggregateRoot : class, IAggregateRoot;
31     }

  UnitOfWork的具體操做會在EntityFrameworkRepositoryContext中完成,並在EntityFrameworkRepository中註冊IEntityFrameworkRepositoryContext接口類型映射,EntityFrameworkRepository做用就是在Repository集合中去完成持久化,工做單元的持久化,看下EntityFrameworkRepositoryContext中的示例代碼:

 1 using System.Data.Entity;
 2 using System.Threading;
 3 
 4 namespace ByteartRetail.Domain.Repositories.EntityFramework
 5 {
 6     public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext
 7     {
 8         private readonly ThreadLocal<ByteartRetailDbContext> localCtx = new ThreadLocal<ByteartRetailDbContext>(() => new ByteartRetailDbContext());
 9 
10         public override void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
11         {
12             localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Deleted;
13             Committed = false;
14         }
15 
16         public override void RegisterModified<TAggregateRoot>(TAggregateRoot obj)
17         {
18             localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Modified;
19             Committed = false;
20         }
21 
22         public override void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
23         {
24             localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Added;
25             Committed = false;
26         }
27 
28         public override void Commit()
29         {
30             if (!Committed)
31             {
32                 localCtx.Value.SaveChanges();
33                 Committed = true;
34             }
35         }
36 
37         public override void Rollback()
38         {
39             Committed = false;
40         }
41 
42         protected override void Dispose(bool disposing)
43         {
44             if (disposing)
45             {
46                 if (!Committed)
47                     Commit();
48                 localCtx.Value.Dispose();
49                 localCtx.Dispose();
50                 base.Dispose(disposing);
51             }
52         }
53 
54         #region IEntityFrameworkRepositoryContext Members
55 
56         public DbContext Context
57         {
58             get { return localCtx.Value; }
59         }
60 
61         #endregion
62     }
63 }

  UnitOfWork的操做會貫徹全部Repository的持久化,在Byteart Retail項目中的領域層,有不少的類和接口關聯,好比IEntity、IAggregateRoot、IRepository、IRepositoryContext、Repository、RepositoryContext、EntityFrameworkRepositoryContext等等,用類圖表示有時候不太直觀,畫了一個簡單的示例圖,方便理解UnitOfWork在DDD中的應用始末

點擊查看大圖

  左半部分:IEntity、IAggreateRoot、IRepository<TAggregateRoot>、Repository<TAggregateRoot>等,能夠看作是倉儲庫,和領域模型相關(存在於領域層),右半部:IUnitOfWork、IRepositoryContext、RepositoryContext、IEntityFrameworkRepositoryContext等,能夠看作是倉儲的持久化(工做單元),這二者經過EntityFrameworkRepository進行IoC註冊對象,完成全部Repository的整個工做單元的協調、管理。

後記

  You don't know you're beautiful,that's what makes you beautiful ! -你不知道你是如此的美麗動人,這就是你美麗動人的所在!

  若是你以爲本篇文章對你有所幫助,請點擊右下部「推薦」,^_^

  參考資料:

相關文章
相關標籤/搜索