Общий шаблон репозитория в DDD с CQRS, имеет ли смысл? - PullRequest
0 голосов
/ 07 ноября 2018

Что-то беспокоит меня по поводу шаблона хранилища

Какова реальная цель хранилища? Я понимаю это как часть Domain.Model, что-то, что предоставляет средства для выполнения команд на агрегатах, и это все.

Теперь, если вы используете универсальный базовый репозиторий, который предоставляет средства для CUD, вы можете сказать, что ваш домен не является универсальным, поэтому репозиторий не является универсальным, и я согласен, но только с одной точки зрения, что запросы отправляются, а не команды.

Я упал, что общий репозиторий устраняет необходимость в Domain.Repositories, по крайней мере, в контексте DDD, смешанного с CQRS (я знаю, что это может показаться противоречивым, и это именно то, как я упал). Но если вы отделите свои команды от запросов, то у вас будут WriteRepositories, содержащие только операции CUD. Таким образом, имея много дубликатов повсюду.

Представь себе это

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 репо

Так имеет ли смысл общий репозиторий в контексте DDD, использующего шаблон CQRS, где у вас есть Command.Stack + Query.Stack? И, если да, устраняет ли он необходимость в Domain.Repositories (репозитории команд)?

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Какова реальная цель хранилища?

Глава 6 Эванса ( синяя книга ) довольно подробно описывает схему хранилища. Хранилища "создают иллюзию коллекции в памяти ...."

Хранилище снимает с клиента огромную нагрузку, которая теперь может говорить с простым, выявляющим намерения интерфейсом, а также с тем, что ему нужно с точки зрения модели

Они отделяют дизайн приложений и доменов от технологии персистентности, нескольких стратегий баз данных или даже от нескольких источников данных.

Это не является частью модели предметной области и напрямую не поддерживает выполнение команд. Вместо этого это абстракция, которая отделяет код, который понимает поведение домена (через API агрегатных корней), от кода, который понимает, как выполнять поиск данных и преобразование между постоянными представлениями и представлениями в памяти.

Я понимаю это как часть Domain.Model, что-то, что предоставляет средства для выполнения команд для агрегатов, и это все.

Не совсем? Корни агрегатов являются частью доменной модели, как и фабрики, которые знают, как их собирать.

Но репозитории на самом деле не являются частью модели предметной области; модель предметной области вообще не использует репозитории; прикладной уровень потребляет их, инфраструктурный уровень обеспечивает реализации.

Так что общий репозиторий имеет смысл в контексте DDD с использованием шаблона CQRS

Ну, парень, который популяризировал шаблон CQRS, не был большим поклонником универсальных интерфейсов репозитория .

0 голосов
/ 08 ноября 2018

Я не думаю, что CQRS обязательно окажет какое-либо реальное влияние на дизайн репозиториев. Вам все равно нужно будет сохранять / извлекать ваши агрегаты.

Однако при использовании источника событий картина несколько меняется, поскольку хранилище событий будет действовать как хранилище для абсолютно всех агрегатов.

0 голосов
/ 08 ноября 2018

Вы бы использовали универсальный репозиторий, если у вас возникнет проблема, которая принесет пользу ... в противном случае не используйте универсальный репозиторий ... вы также можете определить универсальный базовый репозиторий, и ваши другие репозитории наследуют общие функции от это:

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
}

Опять же, выбор универсального репозитория зависит от характера вашей проблемы ...

...