Pozyskiwanie zdarzeń i generowanie modeli odczytu

Zakładając problem domeny przepełnienia stosu i następującą definicję zdarzeń:

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

Zakładając następujący stan magazynu zdarzeń (w kolejności pojawienia się):

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

Zakładając następujący denormalizowany model odczytu dla listy pytań (dla pierwszej strony SO):

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

Oraz następujący handler zdarzeń (który buduje denormalizowany model odczytu):

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? */);
        ...
    }
}

Moje pytanie brzmi Jak mogę znaleźć nazwę Użytkownika który zadał pytanie? Lub więcej często: jak powinienem obsługiwać zdarzenia, jeśli mój denormalizowany model odczytu wymaga dodatkowych danych, które nie istnieją w danym zdarzeniu?

Zbadałem istniejące próbki CQRS, w tym SimpleSQRS Grega Younga i fohjin próbkę Marka Nijhofa. Ale wydaje mi się, że są one działać tylko z danymi, które są zawarte w wydarzeniach.
Author: Dmitry Schetnikovich, 2010-10-31

3 answers

Wystarczy wzbogacić wydarzenie o wszystkie niezbędne informacje.

Podejście Grega, o ile pamiętam, wzbogaciło wydarzenie tworząc i przechowując/publikując w ten sposób.

 3
Author: Rinat Abdullin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-03 08:29:55

Osobiście uważam, że nie ma nic złego w sprawdzaniu nazwy użytkownika z poziomu obsługi zdarzenia. Ale jeśli jesteś w sytuacji, w której nie możesz odpytywać nazwy z modelu odczytu użytkownika, wprowadziłbym dodatkowy handler zdarzeń do QuestionEventsHandler, aby obsłużyć Zdarzenie UserRegistered.

W ten sposób QuestionEventsHandler może utrzymywać własne repozytorium nazw użytkowników (nie musisz przechowywać wiadomości e-mail użytkowników). Zapytany handler może następnie odpytywać użytkownika nazwa bezpośrednio z własnego repozytorium (jak powiedział Rinat Abdullin przechowywanie jest tanie!).

Poza tym, ponieważ model questionitem read zawiera nazwę użytkownika, musisz również obsługiwać zdarzenie UserNameChanged w QuestionEventsHandler, aby upewnić się, że pole nazwy w QuestionItem jest aktualne.

Wydaje mi się to mniej wysiłku niż "wzbogacanie wydarzeń" i ma tę zaletę, że a nie budowanie zależności od innych części systemu i ich modeli odczytu.

 22
Author: Chris Moutray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-06 14:46:05

Pobieranie zdarzeń z EventStore.

Pamiętaj - twoje modele do odczytu muszą mieć już dostęp tylko do odczytu do EventStore. Modele odczytu są jednorazowe. Są to po prostu widoki buforowane. W każdej chwili możesz usunąć / wygasnąć odczytywane modele - i automatycznie przebudować je z EventStore. Tak więc-Twoi ReadModelBuilders muszą już być w stanie odpytywać o przeszłe zdarzenia.

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
    }
}

Również uświadomić sobie-repozytorium EventStore nie musi być prawdziwym EventStore, chociaż z pewnością może być. Zaletą systemów rozproszonych jest to, że możesz łatwo replikować EventStore, jeśli potrzebujesz, bliżej swoich Readmodeli.

Natknąłem się dokładnie na ten sam scenariusz... gdzie potrzebowałem więcej danych niż było dostępne w jednym wydarzeniu. Jest to szczególnie ważne w przypadku zdarzeń typu Create, które wymagają wypełnienia nowego modelu ReadModel stanem początkowym.

From Read Models: możesz pobierać z innych Read Models. Ale naprawdę nie polecam tego, jak ty wprowadziłoby wielką kulę zależności, w której poglądy zależą od poglądów.

Dodatkowe dane w zdarzeniach: naprawdę nie chcesz wypełniać swoich wydarzeń dodatkowymi danymi potrzebnymi do wyświetlenia. To naprawdę boli, gdy Twoja domena się zmieni i musisz przenieść wydarzenia. Zdarzenia domenowe mają określone cele-reprezentują zmiany stanu. Nie wyświetlanie danych.

Hope this helps -

Ryan

 -1
Author: Ryan D. Hatch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-11 20:12:48