【问题标题】:One big repository vs. many little ones?一个大存储库与许多小存储库?
【发布时间】:2011-09-12 02:01:54
【问题描述】:

我的数据库中有几个产品表:

  • 产品类型
  • 产品类别
  • ProductCategoryItems
  • 产品库存

按照我现在看到的方式,我可以制作 IProduct,它具有以下方法:

  • FindAllTypes()
  • FindAllCategories(int typeId)
  • FindAllItems(int categoryId)

或者,我可以将它们分开以模仿表结构:IProductType、IProductCategory 等。

有理由选择一个而不是另一个?

【问题讨论】:

    标签: c# asp.net-mvc design-patterns architecture


    【解决方案1】:

    存储库的理念是让每个存储库负责单个实体。在这种情况下,建议为每个实体创建一个存储库。您也可以选择大型存储库,但这不是最佳解决方案。最后你会得到一个包含很多方法并且耦合非常紧密的巨大类。也很难进行维护。

    【讨论】:

    • 您将看到每个类的存储库在许多圈子中被标识为反模式。 Eric Evans 在他的《领域驱动设计》一书中建议为每个聚合根创建一个存储库。请搜索这些术语,因为我目前很着急,无法创建链接。
    【解决方案2】:

    我不认为拥有一个巨大的存储库真的是一个好主意,那么你基本上会有一个可以做所有事情的数据访问上帝类。

    我喜欢有一个基础Repository<T>,它执行常见的操作,例如GetByIdGetAll。我通常让我所有的存储库都继承这个基类来免费获取常用方法,所以我不必一直重写相同的代码。

    【讨论】:

    • +1 表示基本 Repository<T>。我见过这么多存储库实现重复这些常用方法而不使用基类!啊!
    • 我同意这一点。 GenericRepository<T>ftw! +1
    【解决方案3】:

    在我看来,这在很大程度上取决于业务领域模型,确定您的主要业务实体是非常重要的。不一定数据库中的每个表都直接映射到业务实体。表格只是关系数据库以标准化方式表示的一个或多个实体。

    尝试超越规范化关系数据库的限制来描绘您的域模型,真的有不止一个业务概念吗?存储库应围绕坚实、完整、一流的业务实体构建。

    我的建议是拥有一个 IProductRepository 和必要的方法来实现 CRUD 操作并根据需要进行扩展。您不想获得过于雄心勃勃的界面,因为您可能不需要其中的大部分,这可能是一种负担。接口的重要之处在于将您的代码与持久性模式解耦,这样您就可以提供在它们之间切换的灵活性。

    也许在未来,企业需要发展到更详细地代表产品的供应商,例如,在那个时候,您将使用您的良好判断力来决定是否代表一个重要的企业实体值得是否有专用存储库。

    希望这会有所帮助。

    【讨论】:

    • 当然,有些实体只能作为其他实体的子实体存在,它们是同一存储库下的完美候选者
    【解决方案4】:

    我不同意其他人(编辑:艾萨克除外)。小型存储库是一个门面(不是模式)。

    如果实体类型是耦合的(彼此具有导航属性),那么它们就不是真正可分离的。

    修改一种实体类型并提交更改可能会将更改提交给其他实体。

    此外,您不能在同一工作单元之上创建任何小型存储库, 因为 ORM 只有有限数量的实体映射到数据库。

    将您的模型划分为可分离的域,并为每个域创建一个特定的工作单元。

    在这些工作单元上,为您可能需要立即访问的每个实体类型创建 aggregate roots

    每个根都应该有专门键入的 add、remove、getbykeys、query 等方法。

    工作单元上应该有 commitchanges 和类似的方法。

    每个根都类似于其他提到的小型存储库,但是,工作单元是真正的中型存储库(您的模型可能有不止一种类型的存储库)。

    例子:

    // Create one of these
    interface IUnitOfWork
    {
        void Commit();
    }
    
    // Create one of these
    interface IEntitySet<TEntity> where TEntity : class
    {
        void Add(TEntity entity);
        void Remove(TEntity entity);
        TEntity Create<TSpecificEntity>() where TSpecificEntity : TEntity;
    
        IQueryable<TEntity> Query();
    }
    
    // Create one of these per entity type
    interace IEntitySetOfTEntity1 : IEntitySet<Entity1>
    {
        TEntity1 GetByKeys(int key1);
    }
    
    interace IEntitySetOfTEntity2 : IEntitySet<Entity2>
    {
        TEntity1 GetByKeys(short key1, short key2);
    }
    
    // Create one of these per separatable domain
    interface IDomain1UnitOfWork : IUnitOfWork
    {
        IEntitySetOfTEntity1 Entity1s
        {
            get;
        }
    
        IEntitySetOfTEntity2 Entity2s
        {
            get;
        }
    }
    

    所有这些接口及其实现都可以自动生成。

    这些接口及其实现非常轻巧,绝不是“具有大量方法的巨大类”。由于它们可以自动生成,因此易于维护。

    可以使用以下方法将特定功能添加到接口 IDomain1UnitOfWork、IEntitySetOfTEntity1 等:
    一种。扩展方法
    湾。部分接口和类(不太推荐,因为这会导致 DAL 不太干净)

    如果您使用扩展方法将 GetByKeys() 方法添加到 IEntitySet,则可以忽略 IEntitySetOfTEntity1 类接口。

    【讨论】:

      猜你喜欢
      • 2011-04-24
      • 1970-01-01
      • 2020-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-16
      相关资源
      最近更新 更多