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

Generic Repository Pattern in DDD with CQRS, does it make sense?

存储库模式让我有些困扰

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

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

我觉得通用存储库消除了对 Domain.Repositories 的需要,至少在 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个回购

那么,在使用 CQRS 模式的 DDD 上下文中使用 Command.Stack + Query.Stack 的通用存储库是否有意义?如果是这样,它是否消除了对 [=26= 的需要? ](命令存储库)?

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

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
}

同样,通用存储库的选择与问题的性质有关...

What is the actual purpose of a repository ?

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

A REPOSITORY lifts a huge burden from the client, which can now talk to a simple, intention-revealing interface, and as for what it needs in terms of the model

They decouple application and domain design from persistence technology, multiple database strategies, or even multiple data sources.

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

I understand it as a part of Domain.Model, something that provides means of executing commands on aggregates and that is it.

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

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

So does a generic repository makes sense in the context of DDD using CQRS pattern

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

我认为 CQRS 不一定会对存储库的设计产生任何实际影响。您仍然需要 persist/retrieve 您的聚合。

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

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