CQRS - создание BaseCommandHandler с использованием Mediatr на C#, ASP.net Core

Так я узнал о Mediatr, созданном Джимми Богардом, и меня действительно поразило, как мы достигаем паттерна CQRS с помощью Mediatr.

Я начал реализовывать это в своем приложении, а затем понял, что в моем приложении могут быть сотни Entities, и для каждой Entity я не уверен в создании отдельных команд и запросов, что было бы полной противоположностью DRY. Итак, я начал писать базовые команды и обработчики.

public abstract class CreateBaseCommand : IRequest
{    
}

public abstract class DeleteBaseCommand : IRequest
{
}  //... and so on.

И соответствующие обработчики.

public abstract class CreateBaseHandler : IRequestHandler<CreateBaseCommand>
{
}

public abstract class DeleteBaseCommandHandler : IRequestHandler<DeleteBaseCommand>
{
}//... and so on.

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

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

    public abstract class BaseCommand : IRequest
    { 
       int CommandType
    }

    public abstract class BaseCommandHandler : IRequestHandler<BaseCommand>
    {
       public Task<Unit> Handle(BaseCommand request, CancellationToken cancellationToken)
       {
        if (CommandType == 0)
        {
            // Create entity
        }
        if (CommandType == 1)
        {
            // Update entity
        }//.. and so on
      }
    }

Мне было интересно, есть ли более эффективный способ сделать это, я не очень убежден в идее использования CommandType и у меня есть один метод handle для выполнения всех операций CRUD.

Это хороший подход или мне нужно иметь отдельный набор команд для каждого объекта домена?

С CQRS вы разделяете вещи. Но затем вы вводите базовую команду, чтобы объединить все это воедино. Это просто плохое применение CQRS. Мы испробовали ваш подход - все закончилось слезами. А команд у нас сотни. Не каждую СУХО стоит внедрять.

trailmax 29.11.2018 11:18

@trailmax Итак, вы предлагаете иметь отдельные команды для каждой сущности?

Dheeraj Kumar 29.11.2018 11:22

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

trailmax 29.11.2018 12:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
2 278
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

Например, предположим, что вы пишете систему розничной торговли и создаете новый заказ для зарегистрированного пользователя, и в этом заказе 5 позиций. Глядя на это с точки зрения модели данных, вам нужно отправить 1 команду создания для заказа и 5 команд создания для позиций. Что должно произойти, так это отправить одну команду AddNewOrderCommand и поручить классу User ее обработать. Затем метод класса User создает новую строку базы данных заказов и все позиции. То, как вы добавляете порядок (какие строки создавать и т. д.), Теперь инкапсулируется в методе, которому он принадлежит, а не в вашей командной архитектуре.

Вы используете для своего приложения дизайн, ориентированный на домен? Если нет, вам следует рассмотреть это, потому что он очень хорош для сложных систем, и если у вас есть сотни объектов, шансы хорошие, это квалифицируется как сложная система. На языке DDD указанный выше Пользователь называется, а агрегированный корень, а также заказ и статья являются просто объектами. У вас нет команд создания для сущностей, только для агрегированных корней. (Обратите внимание, что класс иногда может быть как совокупным корнем, так и нормальным объектом в другом совокупном корне. Почему это происходит и как с этим справиться, выходит за рамки этого вопроса)

Просмотрите свою модель и найдите вещи, которые не имеют смысла, если они не принадлежат кому-то другому. Например, позиция из приведенного выше примера. Не имеет смысла иметь в моей базе данных позицию, не связанную с заказом. Следовательно, все позиции должны создаваться по заказам. Наличие заказа без связанного с ним пользователя также не имеет смысла. Следовательно, пользователь должен создать заказ. Однако кажется, что пользователь находится на вершине пирамиды, так что это совокупный корень, и ему нужна команда Create.

Если вы проанализируете свой домен, то обнаружите, что вам не нужно так много команд Create, и проблема исчезнет.

Спасибо, что ответили. Я не получил часть ". У вас нет команд создания для сущностей, только для агрегированных корней". Можете ли вы указать мне какое-нибудь направление здесь?

Dheeraj Kumar 29.11.2018 11:39

Для начала вам нужно понять разницу между Aggregate Root и Entity. Гугл то и все станет ясно.

Brad Irby 29.11.2018 11:47

Ах. Я понял, поэтому CreateCommands нужны только для агрегированных корней, а все остальные команды - для других сущностей. Это правильно?

Dheeraj Kumar 29.11.2018 11:54

Да, по определению объекты, которые не являются совокупными корнями, принадлежат совокупному корню, и именно этот корень должен создавать объект в ответ на команду «бизнес-идея». Следовательно, вам не нужна команда создания для сущностей.

Brad Irby 29.11.2018 11:57

Спасибо. Это полезно.

Dheeraj Kumar 29.11.2018 12:00

@DheerajKumar Этот парень кое-что понял. Полностью согласен с тем, что он сказал здесь, подтверждается моим более чем 5-летним опытом работы с CQRS.

trailmax 29.11.2018 12:52

Другие вопросы по теме