倉儲模式

Repository模式自2004年首次做爲領域驅動設計的一部分引入以來,已經得到了至關多的知名度。本質上,它提供了數據的抽象,以便您的應用程序可使用具備接口近似的簡單抽象一個集合的。從這個集合中添加,刪除,更新和選擇項目是經過一系列直接的方法完成的,無需處理鏈接,命令,光標或讀取器等數據庫問題。使用這種模式能夠幫助實現鬆耦合,而且能夠保持領域對象的持久性無知雖然這種模式很是流行(或者也許正由於如此),但它也常常被誤解和誤用。有不少不一樣的方式來實現Repository模式。讓咱們考慮其中的一些,以及它們的優勢和缺點。數據庫

每一個實體或業務對象的存儲庫

最簡單的方法,特別是對於現有系統,是爲每一個須要存儲或從持久層檢索的業務對象建立一個新的Repository實現。此外,您只應實現您在應用程序中調用的特定方法。避免建立必須爲全部存儲庫實施的「標準」存儲庫類,基類或默認接口的陷阱。是的,若是你須要一個Update或Delete方法,你應該努力使它的接口保持一致(Delete帶一個ID,仍是帶對象自己?),可是不要在你的LookupTableRepository上實現一個Delete方法你只會打電話給List()。這種方法最大的好處是  YAGNI  - 你不會浪費任什麼時候間來實現永遠不會被調用的方法。設計模式

通用儲存庫接口

另外一種方法是繼續爲您的Repository建立一個簡單的通用界面。你能夠約束它的工做類型是什麼類型,或者實現一個特定的接口(例如確保它有一個Id屬性,以下面使用基類所作的那樣)。通用C#存儲庫接口的一個例子多是:安全

這種方法的優勢是它能夠確保你有一個通用的界面來處理你​​的任何對象。您還可使用通用存儲庫實現(如下)簡化實現。請注意,接受謂詞消除了返回IQueryable的必要性,由於能夠將任何過濾器詳細信息傳遞到存儲庫中。儘管如此,這仍然可能致使數據訪問細節泄漏到調用代碼中。若是遇到問題,請考慮使用規範模式(以下所述)來緩解此問題。框架

通用存儲庫實現

假設您建立了一個通用儲存庫接口,您也能夠通常地實現該接口。完成此操做後,您能夠輕鬆建立任何給定類型的存儲庫,而無需編寫任何新代碼,而聲明依賴關係的類能夠簡單地指定IRepository <Item>做爲類型,而且您的IoC容器很容易與之匹配與一個存儲庫<Item>實現。您能夠在這裏看到使用實體框架的示例通用存儲庫實現。spa

請注意,在此實現中,全部操做都在執行時保存; 沒有適用的工做單元。工做單元行爲能夠經過多種方式添加到此實現中,其中最簡單的方法是將明確的Save()方法添加到IRepository <T>方法,並僅調用基礎的SaveChanges()方法從這個方法。設計

IQueryable的?

存儲庫的另外一個常見問題與他們返回的內容有關。他們應該返回數據,仍是應該返回能夠在執行前進一步細化的查詢(IQueryable)?前者更安全,但後者提供了很大的靈活性。實際上,若是你使用IQueryable路由,你能夠簡化你的接口,只提供一種讀取數據的方法,由於從那裏能夠返回任意數量的項目。code

這種方法的一個問題是它每每會致使業務邏輯滲透到更高的應用程序層,並在那裏重複。若是返回有效客戶的規則是他們沒有被禁用,而且他們在去年購買了某些東西,那麼最好是有一個方法ListValidCustomers()來封裝這個邏輯,而不是在多個lambda表達式中指定這些條件不一樣的UI層對存儲庫的引用。實際應用中的另外一個常見示例是在實體上使用由IsActive或IsDeleted屬性表示的「軟刪除」。一旦項目被刪除,99%的時間應該被排除在任何UI場景中顯示,因此幾乎每一個請求都會包含相似對象

.Where(foo => foo.IsActive)blog

除了存在的其餘過濾器以外。這能夠更好地在存儲庫中實現,它能夠是List()方法的默認行爲,也能夠將List()方法重命名爲ListActive()。若是確實須要查看已刪除/不活動的項目,則可使用特殊的List方法來實現此目的(可能不多見)。接口

規範
遵循不公開IQueryable的建議的存儲庫一般會因許多自定義查詢方法而變得臃腫。解決方案是使用規範設計模式將查詢分解爲它們本身的類型規範能夠包括用於過濾查詢的表達式,與該表達式相關的任何參數,以及查詢應該返回多少數據(即EF / EF Core中的「.Include()」)。結合存儲庫和規範模式能夠很好地確保您在數據訪問代碼中遵循單一責任原則查看如何在C#中實現通用存儲庫以及通用規範的示例

相關文章
相關標籤/搜索