Я хочу реализовать свое первое приложение, используя шаблон CQRS вместе с Event Sourcing. Мне интересно, как с созданием совокупных корней нужно обращаться правильно. Допустим, кто-то отправляет команду CreateItem. Как это должно быть обработано? Где должно храниться событие ItemCreated? Как первое событие нового предмета? Или у меня должна быть какая-то сущность ItemList, которая объединяет все элементы, а ее список событий состоит только из событий ItemCreated?
Уди Дахан предлагает не создавать совокупные корни и всегда использовать вместо этого какой-то метод извлечения. Но как я могу получить что-то новое и, конечно, не назначенный идентификатор. Я понимаю идею, лежащую в основе, и вполне разумно думать, что новый объект - это объект, состояние которого состоит из нулевых событий, ответивших на него. Но как мне это использовать? Должен ли я иметь отдельный метод в моем репозитории, например, getNewItem()
или сделать мой get(id)
метод принятия Optional<ItemId>
вместо этого?
Редактировать: После некоторого времени копания я нашел действительно интересную реализацию вышеупомянутых шаблонов с использованием актеров. Автор вместо того, чтобы создавать агрегат, извлекает его из какого-то репозитория с недавно созданным UUID. Недостаток этого подхода заключается в том, что он допускает временное несоответствие состояния. Мне также интересно, как я могу реализовать delete
метод с таким подходом. Просто добавить удаленное событие в список событий агрегата?
Ответы:
Идея в посте Уди, как я понимаю, заключается в том, что ни один предмет не появляется из воздуха. Существует (почти) всегда что-то, или, более конкретно, некоторая операция с доменом, которая привела к созданию элемента. Точно так же, как пример Уди, когда пользователь действительно родился от посетителя, зарегистрировавшегося на сайте. В этой точке и в этом ограниченном контексте посетитель является совокупным корнем, который извлекается по его IP-адресу. Затем этот посетитель создает новый «элемент», пользователь на этом этапе, через операцию домена, называемую « Регистрация» . То же самое относится и к предыдущему шагу, который является еще одним ограниченным контекстом: Referrer - это AR, который извлекается URL-адресом и имеет доменную операцию с именем BroughtVisitorWithIp , где родился посетитель.
Уди также очень хорошо пишет об удалении: http://www.udidahan.com/2009/09/01/dont-delete-just-dont/ . Основная идея в том, что вы ничего не удаляете, никогда. За этим всегда стоит доменная операция, которую мы хотим зафиксировать. Как заказ отменяется, а не удаляется. Прочитайте это, это очень хороший пост.
Главное в обоих случаях, связанных с DDD и особенно Event Sourcing, заключается в том, что вы никогда не должны выполнять прямые CRUD-операции. Если вы оказались в ситуации, когда вам действительно нужно просто вставить, обновить или удалить некоторые данные, а за ними действительно нет операции домена, то, возможно, DDD и Event Sourcing не очень подходят для этого ограниченного контекста . Вы можете комбинировать эти два значения по своему усмотрению, пока один ограниченный контекст придерживается одного принципа. Таким образом, ограниченный контекст в стиле CRUD может создать некоторую строку в базе данных, которая станет сущностью и Агрегированным корнем в другом ограниченном контексте, где вы теперь можете получить AR и не создавать его.
источник