使用Entity Framework时是否真的有必要实现存储库?

时间:2010-09-23 13:31:06

标签: entity-framework repository

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

4 个答案:

答案 0 :(得分:5)

您可以根据自己的建议对控制器进行测试。

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

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

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

如果你能在不连接数据库(或网络服务)的情况下做到这一点,那就太好了。这就是Repository的用武之地。

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

唯一令这种混淆的事情是大量的示例显示控制器直接与存储库对话。 (S#arp架构,我在看你。)如果你正在查看这些例子,并且你已经有了服务层,那么我同意这很难看出存储库的好处是什么。但是如果你只考虑服务层本身的测试,并且不打算让控制器直接与存储库对话,那么它就会变得更有意义。

答案 1 :(得分:2)

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

某些域驱动设计人员会建议您应该从控制器调用服务(与Web服务不同),但DDD通常应用于复杂域。在简单的应用程序中,您正在做的事情很好并且可以测试。

答案 2 :(得分:0)

您缺少的是更新,创建和删除对象的能力。如果那不是问题,那么界面可能就好了(尽管我会让它从IDisposable派生出来以确保你可以随时处理上下文(并测试它))

答案 3 :(得分:0)

存储库模式与实体框架无关,尽管实体框架实现了一个&#34;存储库&#34;图案。 存储库接口(假设IRepositoryProducts)存在于域层中。如果您不想使用域驱动设计,它可以理解域对象,甚至是实体。

但它的实现(假设为RepositoryProducts)是实际的存储库模式实现,并不存在于域层中,而是存在于持久层中。

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

所以答案是:它并不是真的必要,但建议使用Repository模式,尽管使用Entity ORM作为保持域层和持久层之间分离的良好做法。因为这是存储库模式的目的:域逻辑与信息持久化方式之间的关注点分离。当您使用域级别的存储库模式时,您只需抽象自己并思考&#34;我想存储此信息,我不关心它是如何完成的,#34;或者&#34; I想要列出这些东西,我不在乎你从哪里获取它们或者如何检索它们。请给我&#34;。

实体框架与域层无关,它只是一种很好的持久化对象的方式,但应该存在于存储库实现中(持久层)