使用儲存庫模式支持多個提供者
好吧,不確定這是否是完全正確的標題,但基本上我在 MVC 應用程序中使用儲存庫時遇到了很多問題,以至於您可以用一組儲存庫替代另一組儲存庫,實現不同的數據儲存技術。
例如,假設我想為我的應用程序使用實體框架。但是,我還希望在硬編碼列表中實現一組測試數據。我想要一組介面(IUserRepository、IProductRepository 等——我們現在先不討論更通用的 IRepository<T>),這兩種方法都可以實例化。然後,使用(比如)依賴注入工具,例如 Ninject 或 Castle Windsor,我可以在實體框架提供者(訪問實際數據庫)和測試提供者(訪問列表)之間來回切換。
簡而言之,這就是問題所在:
– 如果您要使用實體框架,您希望您的儲存庫返回 IQueryable<SomeType>。
– 如果你打算使用硬編碼列表,你不希望你的儲存庫返回 IQueryable,因為它會極大地增加成本,而且,Linq to Entities 與 Linq to Objects 有很大不同,導致程式碼中的許多問題這對兩個供應商來說都很常見。
換句話說,我發現最好的方法是隔離儲存庫中所有依賴於 EF 的程式碼,以便儲存庫本身返回 IEnumerable 或 IList 或類似的——然後 EF 和其他一些技術都可以使用相同的儲存庫。因此,所有 IQueryable 都將包含在 EF 儲存庫中。這樣,您可以將 Linq to Entities 與 EF 儲存庫一起使用,並將 Linq to Objects 與測試儲存庫一起使用。
然而,這種方法將大量業務邏輯放入儲存庫中,並導致程式碼大量重複——邏輯必須在每個儲存庫中重複,即使實現有些不同。
儲存庫作為這一層非常薄並且僅連接到數據庫的整個想法隨後就失去了——儲存庫是業務邏輯以及數據儲存連接的“儲存庫”。你不能只擁有查找、保存、更新等。
我一直無法解決需要隔離依賴於提供程序的程式碼和將業務邏輯放在一個集中位置之間的這種差異。
有任何想法嗎?如果有人可以向我指出解決此問題的實現範例,我將不勝感激。(我已經閱讀了很多,但找不到任何專門討論這些問題的內容。)
更新:
我想我開始覺得可能不可能有可以為不同的提供者換出的儲存庫——例如,如果你要使用 Entity Framework,你只需要將整個應用程序都用於 Entity Framework . 單元測試?我正在為此苦苦掙扎。到目前為止,我的做法是使用硬編碼數據建立一個單獨的儲存庫,並將其用於單元測試,以及在設置數據庫之前測試應用程序本身。我想我將不得不尋找一個不同的解決方案,也許是一些模擬工具。
但隨之而來的問題是,為什麼要使用儲存庫,尤其是為什麼要使用儲存庫介面。我正在做這件事。我認為確定最佳實踐需要進行一些研究。
我能說什麼?歡迎來到俱樂部 …
您發現的是許多使用 EFv4 跟隨“儲存庫繁榮”的開發人員遇到的問題。是的,這就是問題所在,而且問題真的很複雜。我多次討論過這個問題:
單獨的主題是為什麼要使用儲存庫:
基本上你提出的方法是一個解決方案,但你真的想要它嗎?在我看來,結果不是儲存庫,而是數據訪問對象 (DAO) 暴露了大量的訪問方法。Martin Fowler的儲存庫定義是:
儲存庫在域和數據映射層之間進行調解,就像記憶體中的域對象集合一樣。客戶端對像以聲明方式構造查詢規範,並將它們送出給 Repository 以獲得滿意。對象可以添加到儲存庫中,也可以從儲存庫中刪除,就像它們可以從簡單的對象集合中一樣,儲存庫封裝的映射程式碼將在幕後執行適當的操作。從概念上講,儲存庫封裝了持久化在數據儲存中的一組對像以及對它們執行的操作,從而提供了一個更加物件導向的持久層視圖。儲存庫還支持實現域和數據映射層之間的清晰分離和單向依賴的目標。
我相信公開
IQueryable比創建一個類似於儲存過程時代的儲存庫的公共介面要好 100 倍——每個儲存過程一個訪問方法(固定查詢)。這個問題可以用洩漏抽象的規則來概括。
IQueryable是數據庫查詢的抽象,但提供的功能IQueryable取決於提供者。不同的提供者 = 不同的功能集。什麼是結論?您是否因為測試而想要這樣的架構?在這種情況下,開始使用前兩個連結答案中提出的集成測試,因為在我看來這是最不痛苦的方式。如果您採用建議的方法,您仍應使用集成測試來驗證您的儲存庫隱藏所有與 EF 相關的邏輯和查詢。