在使用实体框架时是否真的需要实现存储库?

问题描述:

我正在学习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的好处。我错过了什么? (对不起,第一篇文章有​​点太长)

你可以用你的建议测试你的控制器。

但是,你如何测试你的查询内的数据服务?想象一下,你有非常复杂的查询行为,用多个复杂的查询返回结果(检查安全性,然后查询Web服务,然后查询EF等)。

你可以把它放在控制器中,但这显然是错误的。

当然,它应该进入你的服务层。您可能会嘲笑/伪造服务层以测试控制器,但现在您需要测试服务层。

这将是很好,如果你可以做到这一点,而无需连接到数据库(或Web服务)。这就是Repository进来的地方。

数据服务可以使用“哑”存储库作为其可以执行复杂查询的数据源。然后,您可以通过使用List<T>作为其数据存储的假实现替换存储库来测试数据服务。

唯一令人困惑的是大量的示例,显示控制器直接与存储库通信。 (S#arp Architecture,我正在看你)。如果你正在查看这些例子,并且你已经有了一个服务层,那么我同意它很难看到这个版本库的好处。但是,如果您只考虑服务层本身的测试,并且不打算让控制器直接与存储库进行对话,那么它开始变得更有意义。

你缺少的是更新,创建和删除对象的能力。如果这不是问题,那么界面可能已经足够好了(尽管我会让它来自IDisposable以确保始终可以处理上下文(并为此进行测试))

+0

好吧,我剥去一切非必要的,只剩下这些线条说明了如果我创建了一个存储库,它将只包含单线或双线方法,这些方法几乎不会增加任何显着价值。 – 2010-09-23 13:40:22

+0

啊,现在我明白你在说什么了。你只是从DBContext中提取一个接口,而不是使用存储库来包装它。 – 2010-09-23 13:54:26

NHibernate项目的Ayende和其他名气agrees with you.

某些域驱动设计人员会建议您应该有一个从您的控制器调用的服务(不同于Web服务)层,但DDD通常应用于复杂的域。在简单的应用程序中,你正在做的是好的和可测试的。

尽管实体框架实现了“存储库”模式,但存储库模式与实体框架无关。 存储库接口(可以说是IRepositoryProducts)位于域图层中。它理解域对象,如果你不想使用域驱动设计,它甚至可以理解实体。

但其实现(可以说RepositoryProducts)是实际存储库模式的实现,并不在域层中,而是在持久层中。

此实现可以使用实体或任何ORM ..或不保留数据库中的信息。

所以答案是:虽然使用Entity ORM作为保持领域层和持久层分离的良好习惯,但建议尽可能使用Repository模式。因为这就是存储库模式的目的:域逻辑与信息保持方式之间的关注点分离。当从域级使用存储库模式时,您只需抽象自己并思考“我想存储这些信息,我不在乎它是如何完成的”,或者“我想要这些东西的列表,我不在乎在哪里做你从他们那里得到他们或者如何找回他们,只要给他们'给我'。

实体框架无关与领域层,它只是将对象持久的好办法,但是应该住在仓库中实现(持久化层)