代码之家  ›  专栏  ›  技术社区  ›  Ivan Gerken

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

  •  6
  • Ivan Gerken  · 技术社区  · 14 年前

    我现在正在研究MVC和EF,在这些主题的文章中我经常看到控制器通过存储库对象来操作数据,而不是直接使用LINQ来实体。

    我创建了一个小的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; }
        }
    }
    

    最后,控制器使用ITinisHopDataService的实现来获取数据,例如用于显示特定类别的产品。

    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 回复  |  直到 9 年前
        1
  •  5
  •   Craig Stuntz    14 年前

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

    但是,如何在数据服务中测试您的查询呢?假设您有非常复杂的查询行为,使用多个复杂的查询返回结果(检查安全性,然后查询Web服务,然后查询EF等)。

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

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

    如果不连接到DB(或Web服务)就可以这样做,那就太好了。这就是存储库的所在。

    数据服务可以使用“哑”存储库作为数据源,在该存储库上它可以执行复杂的查询。然后,您可以用一个使用 List<T> 作为它的数据存储。

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

        2
  •  2
  •   Tim Hoolihan    14 年前

    埃因德的NHibernate项目和其他名声 agrees with you.

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

        3
  •  0
  •   Sander Rijken    14 年前

    您缺少的是更新、创建和删除对象的能力。如果这不是一个问题,那么接口可能已经足够好了(尽管我会让它从 IDisposable 以确保始终可以释放上下文(并为此进行测试)

        4
  •  0
  •   diegosasw    9 年前

    存储库模式与实体框架无关,尽管实体框架实现了一个“存储库”模式。 存储库接口(比如 IRepositoryProducts )生活在域层。它可以理解域对象,如果不想使用域驱动的设计,甚至可以理解实体。

    但是它的实现 RepositoryProducts )是实际的存储库模式实现,不在域层中,而是在 持续层 .

    此实现可以使用实体或任何ORM..

    因此,答案是:这不是真正必要的,但建议使用存储库模式,尽管使用实体ORM作为保持域层和持久层之间分离的良好实践。因为这就是存储库模式的目的: 域逻辑和信息保存方式之间的关注分离 . 当从域级别使用存储库模式时,您只需抽象自己并认为“我想存储这些信息,我不在乎它是如何完成的”,或者“我想要这些信息的列表,我不在乎从何处获取它们,也不在乎如何检索它们”。把它们给我。

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