Я хочу проверить себя на проекции представления в отношении того, может ли концепция посредника просто существовать в модели чтения, обеспечивая при этом мост между командами.
Позвольте мне использовать надуманный пример для объяснения .
Мы размещаем заказ, который вызывает событие OrderPlaced. Затем рабочий процесс включает создание отборочной накладной, которая используется для подготовки отгрузки.
Отборочная отборочная накладная может быть сгенерирована из заказа (или группы заказов) без предоставления какой-либо дополнительной информации из какого-либо внешнего источника или пользователя , Приемлемо ли тогда, что отборочная квитанция может быть представлена исключительно как считанная модель?
Итак:
PlaceOrderCommand -> OrderPlacedEvent
OrderPlacedEvent -> PickingSlipView
Затем менеджер склада может просмотреть отборочную накладную, выбрать линии, которые они хотели бы отправить, а затем выполнить команду PrepareShipment. Событие ShipmentPrepared затем обновит исходный заказ и удалит соответствующие строки из PickingSlipView.
Я знаю, что это игрушечный пример, но у меня есть концептуально похожий случай использования, когда коллега считает, что PickingSlip должен быть доменом. сущность / агрегат сама по себе, так как она концептуально отличается от порядка. Таким образом, у вас есть команды PlaceOrder, GeneratePickingSlip и PrepareShipment.
Команда GeneratePickingSlip, однако, просто берет номер заказа (идентификатор), преобразует данные заказа в объект комплектации и сохраняет объект. Вы не можете изменить или удалить отборочную накладную или выполнить с ней какие-либо действия, кроме как использовать ее для подготовки отгрузки.
Это похоже на введение ненужных накладных расходов на модель записи, поскольку в конечном итоге это просто преобразование. существующей информации для включения другой команды.
Итак (и без углубления в проблемное пространство складов и доставки) ...
Это то, что я предлагаю законный вариант использования для читать модель?
Действуя в качестве посредника между двумя командами, путем преобразования некоторых данных в другое представление. Или, как предлагает мой коллега, должна ли каждая концепция быть представлена в модели записи во всех случаях?
Мне кажется, что мой подход проще и я избегаю ненужной сложности, но я новичок в CQRS и, возможно, поэтому что-то пропущено.
Редактировать - альтернативный пример
Предоставить еще один пример для изучения:
У нас есть книга записей для категорий, где каждая запись информация о товарах и их местонахождении. Книга записей заполняется внешней системой и содержит номера SKU, сопоставленные с доступными местоположениями:
Book of Record (Electronics)
SKU# Location1 Location2 Location3 ... Location 10
XXXX Introduce Remove Introduce ... N/A
YYYY N/A Introduce Introduce ... Remove
Каждая книга записей является сущностью, а каждая строка является объектом значения.
Книга записей используется для создания различных задач (которые сгруппированы в панели задач для назначения человеку). План может охватывать только подмножество мест.
Существуют различные типы задач: один план задач предназначен для человека, который находится на месте, чтобы добавить или удалить товар с полок. Назовите это задачей AllocateStock. Задача другого типа существует для регионального супервизора, управляющего несколькими местоположениями, для проверки того, что стеллажи должным образом соответствуют рекомендациям магазина, скажем, задача CheckDisplay. Для размещения акций нас интересуют как введенные, так и удаленные SKU. Для проверки дисплеев нас интересуют только недавно представленные SKU и т. Д. c.
. Мы изучаем два варианта:
Опция 1
Человек, создающий задачи, имеет представление (модель чтения), которое позволяет ему выбрать книгу рекордов. Скажем, они выбирают электронику и моду. Затем они выбирают одно из нескольких мест. Затем они могут отправить команду, например:
GenerateCheckDisplayTasks(TaskPlanId, List<BookOfRecordId>, List<Locations>)
Затем команды будут организовывать прохождение записей, отфильтровывать ненужные нам места, обрабатывать только «введенные» элементы и создавать соответствующие CheckDisplayTasks для каждый SKU в TaskPlan.
Вариант 2
Другими вариантами является смещение фильтрации на модель чтения перед генерацией задач.
Когда добавляется книга записей, поддерживается модель представления для каждого типа задач. Данные могут быть транспонированы и будут включать только соответствующую информацию. ie. CheckDisplayScopeView может проецировать книгу рекордов на:
Category SKU Location
Electronics (BookOfRecordId) XXXX Location1
Electronics (BookOfRecordId) XXXX Location3
Electronics (BookOfRecordId) YYYY Location2
Electronics (BookOfRecordId) YYYY Location3
Fashion (BookOfRecordId) ... ... etc
При создании задач представление позволяет пользователю выбрать категорию и места, для которых он хочет создать задачи. Возможно, они выбирают категорию Электроника и Местоположение 1 и 3.
Команда теперь:
GenerateCheckDisplayTasks(TaskPlanId, List<BookOfRecordId, SKU, Location>)
Где команда теперь больше не отвечает за логи c, необходимые для фильтрации местоположения, Удаленные и Н / Д предметы и c.
Таким образом, команда для первого параметра просто представляет идентификатор объекта, который преобразуется в задачи, вместе с параметрами фильтра и выполняет всю работу внутри, вероятно, используя доменные службы.
Второй параметр выгружает аспект фильтрации в модель представления, и теперь команда отправляет значения, которые будут генерировать задачи.
Примечание. С точки зрения указаний, что агрегаты не должны появляться из ничего, Агрегат плана задач создаст задачи.
Я пытаюсь определить, возлагает ли вариант 2 слишком большую ответственность на модель чтения, или это поведение фильтрации более применимо там.
Извините Я попытался использовать пример PickingSlip, так как думал, что это будет более узнаваемая проблемная область, но теперь понимаю, что существуют коннотации, которые go наряду с концепцией, которая могла запутать воду.