CQRS/EventStore: как проверить, существует ли агрегат?

В настоящее время я использую EventStore Дж. Оливера и хочу знать, как я могу проверить, существует ли агрегат, когда я делаю свой вызов (GetById(Guid id))?

Следуя тому, как работает CQRS, должен ли я запрашивать прочитанную базу данных или я должен каким-то образом узнать, есть ли соответствующий агрегат в EventStore?


person JD.    schedule 31.01.2012    source источник


Ответы (2)


Как работает EventStore на данный момент, вы создадите новый поток (агрегатный корень), если поток не найден.

Проверьте эту строку: https://github.com/joliver/CommonDomain/blob/master/src/proj/CommonDomain.Persistence.EventStore/EventStoreRepository.cs#L53

Он вызывает этот метод в Магазине: https://github.com/joliver/EventStore/blob/master/src/proj/EventStore.Core/OptimisticEventStore.cs#L45

Который вызывает этот конструктор: https://github.com/joliver/EventStore/blob/master/src/proj/EventStore.Core/OptimisticEventStream.cs#L27

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

Однако не стоит задавать себе этот вопрос. Команда должна быть проверена перед отправкой. Используйте свои модели чтения для проверки команды перед ее отправкой.

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

Обновление в ответ на комментарий Мауроса:

У вас проблема с параллелизмом. Возможно, вы сможете решить эту проблему, используя метод, используемый в случайно соединенных системах, которые объединяются. Что вы можете сделать, так это сохранить версию Stream в модели чтения, чтобы вы знали, с какой версией AR вы действовали. Затем, когда команда обрабатывается, вы знаете, действовали ли вы в старом состоянии AR.

Если версия AR выше, чем та, которую приносит команда, вы можете либо отменить команду как неудачную (пессимистический параллелизм), либо попытаться объединить изменения.

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

Я думаю, что это лучший способ решить проблемы параллелизма такого типа.

Найдите объединение событий для получения дополнительной информации.

person Mikael Östberg    schedule 31.01.2012
comment
Команда должна быть проверена перед ее отправкой. Что, если модель чтения устарела, потому что другой клиент отправляет событие в постоянство? я борюсь с этой проблемой - person Mauro Destro; 01.02.2012
comment
Я обновил ответ, так как он не помещался в поле для комментариев, хотя, возможно, было бы лучше использовать отдельный вопрос. - person Mikael Östberg; 01.02.2012
comment
@MikaelÖstberg: Большое спасибо за информацию. На данный момент я не использовал EventStoreRepository напрямую, поскольку я все еще изучаю CQRS, и у меня были проблемы с работой с CommonDomain. Знаете ли вы о каких-либо проектах/всплесках кода, использующих CommonDomain? - person JD.; 01.02.2012
comment
@JD Здесь есть образец: github.com/etishor/CQRSEventSourcingSample Образец домена немного тонкий но это довольно хорошо, чтобы взглянуть на в любом случае. - person Mikael Östberg; 01.02.2012
comment
@ Микаэлостберг. Большое спасибо. - person JD.; 02.02.2012

Я полагаю, вы на самом деле имеете в виду IRepository.GetById() в проекте CommonDomain Джоливера?

Когда вы вызываете GetById с совокупным корневым идентификатором, которого нет в хранилище событий, репозиторий предоставит вам новый совокупный объект с .Version == 0 и .Id == Guid.Empty. Я только что создал свой собственный производный репозиторий, который обнаруживает это условие и вместо этого возвращает null:

public override TAggregate GetById<TAggregate>(Guid id, int versionToLoad)
{
    var aggregate = base.GetById<TAggregate>(id, versionToLoad);
    return aggregate.Version > 0 ? aggregate : null;
}

Это может быть неправильный способ (см. Ответ Микаэля), но пока у меня это работает нормально.

person Eric Lee    schedule 31.01.2012
comment
На самом деле, я думаю, что где-то читал, что Джонатан Оливер думает об изменении поведения в отношении этой проблемы, поскольку довольно странно неявно создавать и возвращать новый поток при запросе существующего. - person Mikael Östberg; 31.01.2012
comment
@Eric: Спасибо за код. Я обязательно буду использовать его. В настоящее время я не использую EventStoreRepository, и вместо этого, когда я учился, я использовал store.openStream() и т. д. напрямую и до сих пор не имел концепции моментальных снимков. Так что, возможно, пришло время переключиться на EventStoreRepository. - person JD.; 01.02.2012
comment
@Eric: Вы создаете исключение, если агрегат имеет значение null на вашем командном уровне, или было бы лучше создать исключение в GetById‹›, если агрегата нет? - person JD.; 01.02.2012