2010-09-23 62 views
6

我正在學習MVC和EF,我經常在關於這些主題的文章中看到控制器通過Repository對象處理數據,而不是直接使用LINQ to Entities。在使用實體框架時是否真的需要實現存儲庫?

我創建了一個小型web應用程序來測試一些想法。它聲明如下界面作爲數據存儲

public interface ITinyShopDataService 
{ 
    IQueryable<Category> Categories { get; } 
    IQueryable<Product> Products { get; } 
} 

的抽象然後我具有從生成的類TinyShopDataContext(從ObjectContext的繼承)繼承並實現ITinyShopDataService的類。

public class TinyShopDataService : TinyShopDataContext, ITinyShopDataService 
{ 
    public new IQueryable<Product> Products 
    { 
     get { return base.Products; } 
    } 

    public new IQueryable<Category> Categories 
    { 
     get { return base.Categories; } 
    } 
} 

最後,控制器使用ITinyShopDataService的實現來獲取數據,例如,用於顯示特定類別的產品。

public class HomeController : Controller 
{ 
    private ITinyShopDataService _dataService; 

    public HomeController(ITinyShopDataService dataService) 
    { 
     _dataService = dataService; 
    } 

    public ViewResult ProductList(int categoryId) 
    { 
     var category = _dataService.Categories.First(c => c.Id == categoryId); 
     var products = category.Products.ToList(); 
     return View(products); 
    } 
} 

我覺得上面的控制器具有一些積極的屬性。

  • 由於數據服務被注入,它很容易測試。
  • 它使用以實現中立的方式查詢抽象數據存儲的LINQ語句。

所以,我沒有看到在控制器和ObjectContext派生類之間添加Repository的好處。我錯過了什麼? (對不起,第一篇文章有​​點太長)

回答

5

你可以用你的建議測試你的控制器。

但是,你如何測試你的查詢內的數據服務?想象一下,你有非常複雜的查詢行爲,用多個複雜的查詢返回結果(檢查安全性,然後查詢Web服務,然後查詢EF等)。

你可以把它放在控制器中,但這顯然是錯誤的。

當然,它應該進入你的服務層。您可能會嘲笑/僞造服務層以測試控制器,但現在您需要測試服務層。

這將是很好,如果你可以做到這一點,而無需連接到數據庫(或Web服務)。這就是Repository進來的地方。

數據服務可以使用「啞」存儲庫作爲其可以執行復雜查詢的數據源。然後,您可以通過使用List<T>作爲其數據存儲的假實現替換存儲庫來測試數據服務。

唯一令人困惑的是大量的示例,顯示控制器直接與存儲庫通信。 (S#arp Architecture,我正在看你)。如果你正在查看這些例子,並且你已經有了一個服務層,那麼我同意它很難看到這個版本庫的好處。但是,如果您只考慮服務層本身的測試,並且不打算讓控制器直接與存儲庫進行對話,那麼它開始變得更有意義。

0

你缺少的是更新,創建和刪除對象的能力。如果這不是問題,那麼界面可能已經足夠好了(儘管我會讓它來自IDisposable以確保始終可以處理上下文(併爲此進行測試))

+0

好吧,我剝去一切非必要的,只剩下這些線條說明了如果我創建了一個存儲庫,它將只包含單線或雙線方法,這些方法幾乎不會增加任何顯着價值。 – 2010-09-23 13:40:22

+0

啊,現在我明白你在說什麼了。你只是從DBContext中提取一個接口,而不是使用存儲庫來包裝它。 – 2010-09-23 13:54:26

2

NHibernate項目的Ayende和其他名氣agrees with you.

某些域驅動設計人員會建議您應該有一個從您的控制器調用的服務(不同於Web服務)層,但DDD通常應用於複雜的域。在簡單的應用程序中,你正在做的是好的和可測試的。

0

儘管實體框架實現了「存儲庫」模式,但存儲庫模式與實體框架無關。 存儲庫接口(可以說是IRepositoryProducts)位於域圖層中。它理解域對象,如果你不想使用域驅動設計,它甚至可以理解實體。

但其實現(可以說RepositoryProducts)是實際存儲庫模式的實現,並不在域層中,而是在持久層中。

此實現可以使用實體或任何ORM ..或不保留數據庫中的信息。

所以答案是:雖然使用Entity ORM作爲保持領域層和持久層分離的良好習慣,但建議儘可能使用Repository模式。因爲這就是存儲庫模式的目的:域邏輯與信息保持方式之間的關注點分離。當從域級使用存儲庫模式時,您只需抽象自己並思考「我想存儲這些信息,我不在乎它是如何完成的」,或者「我想要這些東西的列表,我不在乎在哪裏做你從他們那裏得到他們或者如何找回他們,只要給他們'給我'。

實體框架無關與領域層,它只是將對象持久的好辦法,但是應該住在倉庫中實現(持久化層)