應用程序框架實戰二十一:DDD分層架構之倉儲(介紹篇)

  前面已經介紹過Entity Framework的工做單元和映射層超類型的封裝,從本文開始,將逐步介紹倉儲以及對查詢的擴展支持。程序員

什麼是倉儲                                                  

  倉儲表示聚合的集合。數據庫

  倉儲所表現出來的集合外觀,僅僅是一種模擬,除了測試之外,沒有理由使用內存中真正的集合來建立倉儲。安全

  不該該爲全部實體創建倉儲,只有聚合才擁有倉儲。框架

  倉儲用來重建已持久化的聚合,而工廠用於新建聚合。性能

使用倉儲的優勢                                                  

  直接使用Entity Framework的DbContext不是很好嗎,爲何還要在DbContext的上方封裝一層倉儲呢,這是否畫蛇添足?單元測試

  不少使用EF的程序員確實是直接使用DbContext,而且他們發現開發起來十分簡單,由於DbContext的接口設計得很是優雅,從接口上看,DbContext就好像全部實體集合的倉庫。測試

  另外一方面,不少使用了倉儲的朋友,都是依葫蘆畫瓢,雖然建立了倉儲,但並無體會到多大好處。spa

  下面簡要介紹使用倉儲將爲你帶來的優勢。設計

從概念上簡化數據操做

  倉儲模擬了某種聚合的集合,而DbContext包含了N種類型的集合。對象

  與倉儲相近的一個數據訪問模式是數據訪問對象(DAO)模式,不少人認爲倉儲不過是數據訪問對象換了一個名詞而已,從技術上說的確如此,倉儲的強大之處在於概念上更簡單。倉儲在概念上表明內存中的集合操做,而數據訪問對象表明數據庫操做,很明顯,集合比數據庫在概念上更簡單。

減小冗餘查詢邏輯

  若是直接使用DbContext,因爲特定查詢邏輯沒有一個固定位置,可能分散到任何地方,這很容易形成冗餘。

  倉儲是封裝特定查詢邏輯的好地方,對於特定的查詢邏輯,放到與聚合相應的倉儲中便可。

下降耦合度

  直接使用DbContext,全部調用代碼與EF實現高度耦合。

  另外一方面,因爲DbContext可以獲取任意實體,這些實體可能位於聚合內部,這樣會破壞聚合的封裝性,同時在任意位置能夠獲取任意對象,因爲缺少約束力而致使更高的耦合。

方便單元測試

  直接使用DbContext只能進行集成測試,必須鏈接到真實數據庫。而領域層只持有倉儲接口,因此測試時很容易替換成模擬實現,從而避開數據庫。

使用倉儲的要點                                                  

使用更具體的倉儲

  通常來說,ICustomerRepository比直接使用泛型的IRepository<Customer>要好。

  爲了定義通用操做,咱們會建立一些泛型基類來實現基礎操做。

  有些人發現不少具體倉儲只是直接繼承泛型倉儲,好比ICustomerRepository和CustomerRepository從泛型的IRepository<Customer>和Repository<Customer>派生,但CustomerRepository自己並無其它什麼代碼。因而不少人學會偷懶,直接使用泛型基類進行操做。

  ICustomerRepository優於IRepository<Customer>的緣由以下。

  1.  概念上更清晰。

  ICustomerRepository從概念上良好表達了該倉儲用於操做客戶,而泛型倉儲能夠操做任何聚合。

  2.  爲特定查詢邏輯提供惟一封裝和訪問點。

  ICustomerRepository能夠將客戶相關的各類複雜查詢封裝起來,而IRepository<Customer>很難對客戶查詢進行封裝,一個辦法是使用擴展方法來完成封裝,不過比起CustomerRepository要麻煩得多,並且實現代碼也更難管理。

  3.  下降耦合。

  泛型IRepository<>能夠在任意位置獲取任意聚合,這比起DbContext要強一些,不會破壞聚合的封裝性,但缺少約束力仍然會致使更高耦合。

  ICustomerRepository經過明確的聲明,只能獲取須要的聚合,從而控制了對象的訪問。

倉儲僅返回與其聚合高度相關的內容

  倉儲能夠返回對應的聚合,也能夠返回聚合相關的統計信息,甚至能夠返回聚合的一個子集。

  有人在倉儲查詢中使用匿名對象,使用匿名對象的緣由很簡單,即爲了進行投影操做,這樣能夠限制Sql查詢返回的列,對於Sql性能調優來說,這可能很是重要,好比使用Sql Server的覆蓋索引。

  可是使用匿名對象進行查詢有不少問題,一個問題是沒法直接做爲結果返回。有人爲了省力,直接使用聚合或其部分子對象做爲返回類型,其結果是對象中的一部分屬性被賦值,另外一部分屬性爲null。這可能致使許多神祕的Bug,另外致使你或其它人對倉儲查詢信心不足,由於這些查詢並不安全,你每當須要調用一個查詢,首先得仔細檢查代碼,看看哪些值是空的,以避免踩到地雷。

  若是要返回聚合的一個子集,須要單獨定義一些對象,以做爲返回類型。工做量雖然比較大,但更加安全和清晰。

  若是須要獲取的內容由多個聚合組成,這個查詢操做應該放入哪一個倉儲中?這種狀況放到哪一個倉儲其實都不合適,更好的辦法是使用一個查詢服務,就好像跨越多個聚合的業務操做須要領域服務同樣。

總結                                                  

1. 倉儲的定義

  倉儲表示聚合的集合。

2. 倉儲的優勢

  • 簡化數據操做
  • 減小冗餘查詢邏輯
  • 下降耦合度
  • 方便單元測試

3. 倉儲的要點

  • 使用更具體的倉儲
  • 倉儲查詢僅返回與其聚合高度相關的內容 

 

 

  因爲倉儲是對數據操做的封裝,包括倉儲基礎,分頁,查詢擴展,查詢對象,查詢條件(規約模式),查詢條件應用(日期範圍與數值範圍查詢)等內容,因此須要多篇文章進行介紹。 

  .Net應用程序框架交流QQ羣: 386092459,歡迎有興趣的朋友加入討論。

  謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/xiadao521/

相關文章
相關標籤/搜索