Условные команды `create` в архитектуре CQRS - PullRequest
0 голосов
/ 29 ноября 2018

Я упросту мою проблему:

Мой LightsState API может принимать 2 типа входных данных: lightOn {lightId: ##} и lightOff {lightId: ##}.(Ввод AMQP здесь важен)

Эти входы хорошо транслируются в 2 команды: TurnLightOnCmd и TurnLightOffCmd.

Эти команды создадут 2 события: LightTurnedOnEvent и LightTurnedOffEvent.

Эти события будут применены к Light Aggregate, и постоянная проекция будет state of the light.

Все хорошо, пока здесь.

Но потому что нет ввода: create light, я не могу сделать CreateLightCmd из этого.Я могу вызвать CreateLightCmd только тогда, когда получу lightOn вход с NEW lightId, чтобы создать Light Aggregate, а затем также применить TurnLightOnCmd к нему.

Я не уверен, каксправиться с этим, а также следовать хорошей практике CQRS.Можно ли вызвать сторону запроса со стороны команды, чтобы проверить, если light exists by id, а затем сначала при необходимости вызвать CreateLightCmd?Или я должен сделать запрос базы данных изнутри командной стороны и оставить стороны команды и запроса разъединенными?Или есть другие способы решения этой проблемы?

Спасибо

Ответы [ 2 ]

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

Можно ли вызвать сторону запроса со стороны команды, чтобы проверить, существует ли источник света по идентификатору, а затем сначала вызвать CreateLightCmd, если необходимо?

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

Обзор: DDD + CQRS + ES очень похож на архитектуру только на DDD.Основная идея заключалась в том, что мы сохраняем информацию в нашем устройстве хранения данных (он же «база данных»).Модель запускается в процессе, который загружает текущее состояние из базы данных, использует команду для вычисления нового состояния, а затем сохраняет это новое состояние в базе данных.

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

Но: шаблоны создания странные .

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

Сюрприз в том, что это отлично .

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

В псевдокоде:

TurnLightOn (cmd) {
    history = getHistory(cmd.lightId)
    if (history.isEmpty) {
        history.append(LightCreatedEvent.from(cmd))
    }
    history.append(LightTurnedOnEvent.from(cmd))
    save(cmd.lightId, history)
}
0 голосов
/ 29 ноября 2018

Взгляните на оригинальный пост Уди Даана «Не создавайте совокупных корней» [0].Ключевые моменты:

  • Не создавать совокупные корни
  • Всегда получать сущность

Это означает, что при вводе командыу вас всегда должен быть агрегат с фактическим агрегатным корневым объектом, инициализированным в состояние по умолчанию.В вашем случае состояние по умолчанию "свет выключен".Вы выполняете команду на этом индикаторе, и теперь она находится в состоянии «индикатор включен».Теперь вы сохраните его в базе данных, и он будет создан.Если ваш домен не заботится о LightCreatedEvent, вам не нужно его моделировать.

[0] http://udidahan.com/2009/06/29/dont-create-aggregate-roots/

...