Подтвердить что ты не робот

Генерация событий и чтение модели

Предполагая проблему домена и следующее определение событий:

UserRegistered(UserId, Name, Email)
UserNameChanged(UserId, Name)
QuestionAsked(UserId, QuestionId, Title, Question)

Предполагая следующее состояние хранилища событий (в порядке появления):

1) UserRegistered(1, "John", "[email protected]")
2) UserNameChanged(1, "SuperJohn")
3) UserNameChanged(1, "John007")
4) QuestionAsked(1, 1, "Help!", "Please!")

Предполагая следующую денормализованную модель чтения для перечисления вопросов (для первой страницы SO):

QuestionItem(UserId, QuestionId, QuestionTitle, Question, UserName)

И следующий обработчик событий (который строит денормализованную модель чтения):

public class QuestionEventsHandler
{
    public void Handle(QuestionAsked question)
    {
        var item = new QuestionItem(
            question.UserId, 
            question.QuestionId, 
            question.Title, 
            question.Question, 
            ??? /* how should i get name of the user? */);
        ...
    }
}

Мой вопрос как я могу найти имя пользователя, кто задал вопрос? Или чаще: как я должен обрабатывать события, если моя денормализованная модель чтения требует дополнительных данных, которых нет в конкретном событии?

Я изучил существующие образцы CQRS, включая SimpleSQRS Грега Янга и Fohjin образец Марка Ниджхофа. Но мне кажется, что они работают только с данными, включенными в события.

4b9b3361

Ответ 1

Просто обогатите событие всей необходимой информацией.

Как я помню, подход Грега - обогащать событие при создании и хранении/публикации его таким образом.

Ответ 2

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

Таким образом, QuestionEventsHandler может поддерживать собственный репозиторий имен пользователей (вам не нужно будет хранить электронную почту пользователей). Обработчик QuestionAsked может затем запросить имя пользователя прямо из своего собственного репозитория (как сказал Ринат Абдуллин, хранилище дешево!).

Кроме того, поскольку ваша модель чтения QuestionItem содержит имя пользователя, вам необходимо обработать событие UserNameChanged в QuestionEventsHandler, чтобы убедиться, что поле имени в QuestionItem является актуальным.

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

Ответ 3

Вытягивать события из EventStore.

Помните - ваши прочитанные модели должны иметь доступ только для чтения к EventStore. Читать модели являются одноразовыми. Это просто кэшированные представления. Вы должны иметь возможность удалять/истекать ваши модели чтения в любое время и автоматически перестраивать ваши ReadModels из EventStore. Таким образом, ваши ReadModelBuilders уже должны иметь возможность запрашивать прошлые события.

public class QuestionEventsHandler
{
    public void Handle(QuestionAsked question)
    {
        // Get Name of User
        var nameChangedEvent = eventRepository.GetLastEventByAggregateId<UserNameChanged>(question.UserId);

        var item = new QuestionItem(
            question.UserId, 
            question.QuestionId, 
            question.Title, 
            question.Question, 

            nameChangedEvent.Name
    }
}

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

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

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

Дополнительные данные в событиях: вы действительно не хотите раздувать ваши события со всеми дополнительными данными, которые вам понадобятся для просмотров. Это действительно повредит вам, когда ваш домен изменится, и вам нужно перенести события. События домена имеют конкретные цели - они представляют изменения состояния. Не просматривать данные.

Надеюсь, что это поможет -

Райан