具有CQRS的DDD中的通用存储库模式,这有意义吗?

时间:2018-11-07 20:05:11

标签: repository domain-driven-design repository-pattern cqrs ddd-repositories

关于存储库模式的事情困扰着我

存储库的实际用途是什么?我将其理解为Domain.Model的一部分,Domain.Model提供了一种对聚合执行命令的方法。

现在,如果您使用的是可用于CUD的通用基础存储库,则您可能会说您的域不是通用的,因此该存储库不是通用的,我同意,但仅从一个角度来看,发出的查询不是命令。

我认为通用存储库消除了对Domain的需求。至少在DDD与CQRS混合使用的情况下,存储库(我知道我可能会引起争议,这也正是我的想法)。但是,如果您从查询中拆分命令,那么您将拥有只包含CUD操作的WriteRepositories。因此到处都有很多重复项。

想象一下

CustomerRepository : ICustomerRepository
{
    void Add(CustomerAggregate agg);
    void Update(CustomerAggregate agg);
}


BookRepository : IBookRepository 
{
    void Add(BookAggregate agg);
}


SubscriptionsRepository : ISubscriptionsRepository
{
     void Add(SubscriptionAggregate agg);
     void Update(SubscriptionAggregate agg);
     void Delete(SubscriptionAggregate agg);
}

......另外5个仓库

那么在具有Command.Stack + Query.Stack?的CQRS模式的情况下,通用存储库在DDD上下文中是否有意义?

4 个答案:

答案 0 :(得分:3)

  

存储库的实际用途是什么?

Evans(the blue book)的第6章非常详细地介绍了存储库模式。存储库“提供了内存中集合的错觉。”

  

资源库减轻了客户的负担,客户现在可以与简单的意图披露界面进行对话,并了解模型的需求

     

它们将应用程序和域设计与持久性技术,多种数据库策略甚至多种数据源脱钩。

它不是域模型的一部分,也不直接支持命令执行。取而代之的是,它是将理解域行为(通过聚合根的API)的代码与理解如何执行数据查找以及如何在持久表示和内存表示之间进行转换的代码分开的抽象。

  

我将其理解为Domain.Model的一部分,Domain.Model提供了一种在聚合上执行命令的方法。

不是吗?聚合根是域模型的一部分,知道如何组装它们的工厂也是如此。

但是存储库实际上并不是域模型的一部分;域模型根本不使用存储库;应用层使用它们,基础架构层提供实现。

  

在使用CQRS模式的DDD上下文中,通用存储库也有意义

嗯,推广CQRS模式的人不是a big fan of generic repository interfaces

答案 1 :(得分:1)

如果您有一个可以从中受益的问题,则可以使用通用存储库...否则,请不要使用通用存储库...您还可以定义通用基本存储库,并让您的其他存储库继承其通用功能它:

public class RepositoryBase<TEntity> : IRepositoryBase<TEntity>
       where TEntity : class
{
    // generic add logic
    public virtual void Add(TEntity entity)
    {
        DbSet.Add(entity);
        Context.SaveChanges();
    }

    // generic update logic
    public virtual void Update(TEntity entity)
    {
        DbSet.Attach(entity);
        Context.Entry(entity).State = EntityState.Modified;
    }
}

现在,在您的子存储库中,您可以覆盖通用定义...例如,在这里,我想为我的一个聚合根目录定义一个存储库,并且希望它覆盖Add逻辑。 ..并继承现有的Update逻辑:

public class MyAggRootRepository<TEntity> : RepositoryBase<MyAggRoot>,
    IMyAggRootRepository<MyAggRoot>
{
    public override void Add(TEntity MyAggRoot)
    {
        if (MyAggRoot.Id > 0 )
        {
            throw new Exception("Invalid request, Id > 0 means model is already added.");
        }

        DbSet.Add(MyAggRoot);
        Context.SaveChanges();
    }

    // happy with the inherited Update logic
}

同样,选择通用存储库是关于您问题的性质...

答案 2 :(得分:0)

我认为CQRS不一定会对存储库的设计产生任何实际影响。您仍然需要保留/检索汇总。

但是,在使用事件源时,图片会有所变化,因为事件存储将充当绝对所有聚合的存储库。

答案 3 :(得分:0)

并非所有域实体都可以删除或更新。我要说的是,拥有一个包含CUD操作的基础存储库,然后从中可以派生自己的EntityRepository,只允许对特定实体有意义的操作是可以的。