使用Entity Framework时,实现Repository是否真的必要?

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派生类之间添加仓库的任何好处。我错过了什么吗? (抱歉,第一篇文章有点长)

4个回答

6
您可以使用您提出的方法对控制器进行测试。但是,如何测试数据服务中的查询呢?想象一下,您有非常复杂的查询行为,需要多个复杂的查询才能返回结果(检查安全性,然后查询Web服务,再查询EF等)。
您可以将其放在控制器中,但这显然是错误的。当然,它应该放在您的服务层中。您可能会模拟/伪造服务层以测试控制器,但现在您需要测试服务层。
如果您可以在不连接到数据库(或Web服务)的情况下完成此操作,那将很好。这就是存储库的作用。
数据服务可以使用“愚蠢”的存储库作为数据源,以执行复杂的查询。然后,您可以通过将存储库替换为使用 List<T>作为其数据存储的虚拟实现来测试数据服务。
唯一让人困惑的是大量的示例显示控制器直接与存储库通信。 (S#arp Architecture,我在看你。)如果您正在查看这些示例,并且已经拥有了服务层,则我同意这使得难以看到存储库的好处。但是,如果您只考虑测试服务层本身,并且不计划让控制器直接与存储库通信,则它开始变得更加合理。

2

Ayende是NHibernate项目和其他知名人士,他同意你的观点。

一些领域驱动设计(DDD)的人建议你应该有一个服务层(不同于Web服务层),从你的控制器中调用。但是DDD通常适用于复杂的领域。在简单的应用程序中,你正在做的就很好,并且可以进行测试。


0

仓储库模式与实体框架无关,尽管实体框架实现了“仓储库”模式。

仓储库接口(假设为 IRepositoryProducts)位于领域层。它理解领域对象,甚至是实体,如果您不想使用领域驱动设计。

但是它的实现(假设为 RepositoryProducts)是实际的仓储库模式实现,不位于领域层而位于持久化层

此实现可以使用 Entity 或任何 ORM ..或不使用来将信息保存到数据库中。

因此答案是:尽管使用实体 ORM,使用仓储库模式并不是真正必要的,但建议这样做,以保持领域层和持久化层之间的分离,因为这就是仓储库模式的目的:在领域逻辑和信息持久化方式之间实现关注点的分离。当从领域级别使用仓储库模式时,您只需抽象出自己的思维:“我想存储这些信息,我不关心它是如何完成的”,或者“我想要这些东西的列表,我不关心您从哪里获取它们或者您如何检索它们。只需要给我。”

Entity Framework 和领域层没有任何关系,它只是一种很好的持久化对象的方式,但应该存在于存储库实现(持久化层)中。


0
你所缺少的是更新、创建和删除对象的能力。如果这不是问题,那么接口可能已经足够好了(尽管我建议让它从IDisposable派生,以确保您始终可以处理上下文(并进行测试))。

好的,我去掉了所有非必要的内容,只留下了那些说明如果我创建了一个仓库,它将只包含单行或两行方法的想法。这些方法几乎不会增加任何明显的价值。 - Ivan Gerken
啊,现在我明白您的意思了。您只是从DBContext中提取一个接口,而不是使用一个仓储库来封装它。 - Sander Rijken

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接