Repository,我可能不會用你
文章目錄
當我們已經在應用程式中使用 ORM(例如 Entity Framework),還需要 Repository 嗎?這個問題就像「要不要使用 ORM」一樣,沒有標準答案。這類「該不該」的問題,有時真的挺傷腦筋。
更新紀錄
何謂 Repository?
按照 Martin Fowler 的定義,「Repository 是領域層與資料對應層之間的媒介,如同存在記憶體中的物件集合。用戶端會建構查詢規格(query specification),並傳遞給 Repository 以執行特定的資料操作.....概念上,Repository 將資料與其相關操作封裝成物件集合,以便用貼近物件導向的方式來存取資料」。
在設計 Repository 時,常見的做法是為每一個「主要的 entity」設計一個 Repository 類別,稱為 aggregate root。例如客戶資料會有對應的 CustomerRepository,產品資料則是 ProductRepository,訂單則是 OrderRepository;這些都是 aggregate roots。至於訂單細項,應該由 OrderRepository 一併負責處理,就不另外設計 OrderItemRepository。
此外,為了減少重複的程式碼(DRY 原則),有些人會使用泛型 Repository。
如果你想看看 Repository 或者分層設計的範例,可以參考:
有了 ORM,還需要 Repository 嗎?
在 ORM--或者說 Entity Framework--還沒那麼成熟的年代,使用 Repository 模式的理由很充分,好處也明顯。可是,當 Entity Framework 和 NHibernate 已經提供了同樣、甚至更多的功能,我們還需要再多加一層 Repository 嗎?
網路上可以找到很多文章,介紹如何搭配 Entity Framework 來設計我們的 Repository。所以「怎麼做」並不是問題,問題在於我們是否該這麼做。
使用 Repository 的理由通常有這幾個:
拿掉 Repository 之後,單元測試還是可以做,只是測試對象改成了商業邏輯層、服務層、或其他更上層的服務;單元測試的粒度可能會粗一點,視情況而定。如果連商業邏輯層都沒有,例如直接在 MVC 應用程式的 Controller 中使用 Entity Framework,單元測試也許會更麻煩一些。
其次,可抽換底層的資料存取元件當然很理想。然而,一旦使用了 Entity Framework,就算我們用 Repository 把它包起來,難保不夠周密,讓某些與 EF 相依的東西悄悄從縫隙中溜出去。除了擔心成本效益,我也懷疑真實世界中有多少案子真的需要而且實際達成了「任意切換 persistence layer」的理想。
至於 Unit of Work,其實 EF 的 ObjectContext 和 DbContext 已經提供了類似的功能。
如此說來,ORM 之上再疊一層 Repository,可能會讓我們費好一番工夫寫一堆不那麼有用、而且長得很像的程式碼,可能增加了程式的複雜性,卻得不到相對比例的好處。因此,在不需要切換 persistence layer 的情況下,比較小而單純的應用程式,我可能不會使用 Repository。如果是比較大型或複雜的系統....嗯,目前我也說不準。
誠如開頭說的,這裡沒有標準答案,有的只是個人主觀的想法(而且以後可能會變)。
文後附上一些參考文章,如果你也碰到類似問題,可以自行研究看看,寫點程式感覺一下,再做決定。
2014-05-08 補充
www.asp.net 網站上的教學文章 Getting Started with EF 5 using MVC 4 裡面有一個步驟是 Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application,可是到了 EF 6 和 MVC 5,新版本的文章 Getting Started with EF 6 using MVC 5 裡面卻把實作 Repository 的步驟拿掉了,如下圖。不知道是不是有什麼原因。
延伸閱讀
更新紀錄
- 2012-11-30:些微潤飾,增加參考資料。
- 2014-05-08:補充一點新發現,增加延伸閱讀文章。
何謂 Repository?
按照 Martin Fowler 的定義,「Repository 是領域層與資料對應層之間的媒介,如同存在記憶體中的物件集合。用戶端會建構查詢規格(query specification),並傳遞給 Repository 以執行特定的資料操作.....概念上,Repository 將資料與其相關操作封裝成物件集合,以便用貼近物件導向的方式來存取資料」。
在設計 Repository 時,常見的做法是為每一個「主要的 entity」設計一個 Repository 類別,稱為 aggregate root。例如客戶資料會有對應的 CustomerRepository,產品資料則是 ProductRepository,訂單則是 OrderRepository;這些都是 aggregate roots。至於訂單細項,應該由 OrderRepository 一併負責處理,就不另外設計 OrderItemRepository。
此外,為了減少重複的程式碼(DRY 原則),有些人會使用泛型 Repository。
如果你想看看 Repository 或者分層設計的範例,可以參考:
- Tom Dykstra 的文章:Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application(對岸有一篇長得很像的文章,乍看以為是翻譯,仔細看又不完全是,供參考:疑似簡體中文版)
- 範例程式:ProDinner - ASP.NET MVC Sample (EF4.4, N-Tier, jQuery)
- 範例程式:EFMVC - ASP.NET MVC 4, Entity Framework 4.3 Code First and Windows Azure
有了 ORM,還需要 Repository 嗎?
在 ORM--或者說 Entity Framework--還沒那麼成熟的年代,使用 Repository 模式的理由很充分,好處也明顯。可是,當 Entity Framework 和 NHibernate 已經提供了同樣、甚至更多的功能,我們還需要再多加一層 Repository 嗎?
網路上可以找到很多文章,介紹如何搭配 Entity Framework 來設計我們的 Repository。所以「怎麼做」並不是問題,問題在於我們是否該這麼做。
使用 Repository 的理由通常有這幾個:
- 方便單元測試。
- 避免上層服務直接依賴 Entity Framework,以便將來可以將 EF 換掉,換成 NHibernate 或其他 ORM。
- 可搭配 Unit of Work 模式來管理交易。
拿掉 Repository 之後,單元測試還是可以做,只是測試對象改成了商業邏輯層、服務層、或其他更上層的服務;單元測試的粒度可能會粗一點,視情況而定。如果連商業邏輯層都沒有,例如直接在 MVC 應用程式的 Controller 中使用 Entity Framework,單元測試也許會更麻煩一些。
其次,可抽換底層的資料存取元件當然很理想。然而,一旦使用了 Entity Framework,就算我們用 Repository 把它包起來,難保不夠周密,讓某些與 EF 相依的東西悄悄從縫隙中溜出去。除了擔心成本效益,我也懷疑真實世界中有多少案子真的需要而且實際達成了「任意切換 persistence layer」的理想。
至於 Unit of Work,其實 EF 的 ObjectContext 和 DbContext 已經提供了類似的功能。
如此說來,ORM 之上再疊一層 Repository,可能會讓我們費好一番工夫寫一堆不那麼有用、而且長得很像的程式碼,可能增加了程式的複雜性,卻得不到相對比例的好處。因此,在不需要切換 persistence layer 的情況下,比較小而單純的應用程式,我可能不會使用 Repository。如果是比較大型或複雜的系統....嗯,目前我也說不準。
誠如開頭說的,這裡沒有標準答案,有的只是個人主觀的想法(而且以後可能會變)。
文後附上一些參考文章,如果你也碰到類似問題,可以自行研究看看,寫點程式感覺一下,再做決定。
2014-05-08 補充
www.asp.net 網站上的教學文章 Getting Started with EF 5 using MVC 4 裡面有一個步驟是 Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application,可是到了 EF 6 和 MVC 5,新版本的文章 Getting Started with EF 6 using MVC 5 裡面卻把實作 Repository 的步驟拿掉了,如下圖。不知道是不是有什麼原因。
延伸閱讀
- [Architecture Pattern] Repository by 克拉克
- 博客園的大牛們,被你們害慘了,Entity Framework從來都不需要去寫Repository設計模式
- Do we need the repository pattern?
- Reviewing my data access layer using the Entity Framework Profiler
- Repository is the new Singleton by Oren
- The wages of sin: Over architecture in the real world by Oren
- Do we need to use the Repository pattern when working in ASP.NET MVC with ORM solutions?
- Is There a Real Advantage to Generic Repository?
- Generic Repository With EF 4.1 what is the point
- Is Unit of Work pattern required in Entity Framework 4.0
- Unit Testing DbContext
- Repository and Unit of Work for Entity Framework (EF4) for Unit Testing