【问题标题】:MVC: What's better, one large repository per db or one per business entity?MVC:每个数据库一个大型存储库还是每个业务实体一个更好?
【发布时间】:2010-07-16 16:46:22
【问题描述】:

这次我有一个更哲学的问题。

大多数 MVC 教程/书籍似乎建议将一个存储库的范围限制在模型的一个方面,并设置多个存储库以涵盖所有模型类。 (例如:ProjectRep、UserRep、ImageRep,最终都映射到同一个数据库。)

我可以看到这将如何简化单元测试,但我无法想象这将如何在现实世界中发挥作用,因为大多数实体之间都存在关系。最后,我总是发现自己每个 DB 连接都有一个巨大的存储库类和一个同样适用于单元测试的 FakeRepository。

那么,你的意见是什么?我应该更加努力地分离存储库吗? ProductRep 是否通过 PurchaseHistory 引用 UserRep 中的数据,反之亦然?不同的代表如何确保他们在访问单个数据库时不会互相锁定?

谢谢, 达菲

【问题讨论】:

    标签: asp.net-mvc design-patterns


    【解决方案1】:

    这适用于现实世界,因为存储库的引擎盖下只有一个引擎。这可以是像 NHibernate 这样的 ORM 或您自己的解决方案。这个引擎知道如何关联对象、锁定数据库、缓存请求等。但业务代码不应该知道这些基础设施细节。

    当您最终拥有一个巨大的存储库时,您实际上所做的是将这个单一引擎暴露给现实世界。因此,您的域代码与隐藏在存储库接口后面的特定于引擎的详细信息混淆。

    S#arp Architecture 很好地说明了 Josh 谈到的存储库是如何实现和工作的。另请阅读 NHibernate 最佳实践article,它解释了 S#arp 的大部分背景。

    坦率地说,我无法想象您的巨大存储库在现实世界中是如何工作的。因为这个想法看起来很糟糕且无法维护。

    【讨论】:

    • 感谢您的周到回复。我希望我可以将它们全部标记为答案。我想我对域模型和数据库之间的 1:1 映射太着迷了,但正如你们都指出的那样,这两者可能完全是不同的野兽。看起来我需要更多地阅读 ORM
    【解决方案2】:

    我发现通过使用泛型和接口,您可以避免编写许多单独的存储库。如果您的域模型是精心设计的,您通常可以使用域对象而不是另一个存储库来导航对象图。

    public class MyDomainObject : IEntity //IEntity is an arbitrary interface for base ents
    {
         public int Id { get; set;}
         public List<DiffObj> NavigationProp { get; set;}
         //... and so on...
    }
    
    public interface IRepository<T> where T : IEntity, class, new()
    {
         void Inert(T entity);
         T FindById(int id);
         //... and so on
    }
    

    使用非常简单,通过使用 IoC,您可以将实现与应用程序的其余部分完全分离:

    public class MyBusinessClass
    {
         private IRepository<SomeDomainObject> _aRepo;
         public MyBusinessClass(IREpository<SomeDomainObject> aRepo)
         {
              _aRepo = aRepo;
         }
         //...and so on
    }
    

    这使得编写单元测试变得轻而易举。

    【讨论】:

    • 看看这个答案,了解如何使用 IoC 来实现它来管理控制器 - stackoverflow.com/questions/2797047/…
    • 我是团结的粉丝——尤其是。随着他们在 2.0 中所做的改进。我已经在 MVC 项目中使用它来做到这一点。
    • 对此+1。请记住,IRepository 不知道它是如何实现的,调用者也不知道。调用者只想要模型对象。如果您在 IRepository 实现中使用 ORM,它将为您处理所有 FK 加载。如果没有,您可以手动执行,只要接口没有改变并且接口与实现没有耦合。
    猜你喜欢
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    • 2019-01-17
    • 2020-03-12
    • 1970-01-01
    • 2013-04-02
    相关资源
    最近更新 更多