2012-09-09 6 views
12

Jest jedna rzecz o CQRS, której nie otrzymuję: Jak zaktualizować odczytany model, gdy podniesione zdarzenie nie zawiera szczegółów potrzebnych do zaktualizowania odczytanego modelu.Zdarzenia CQRS nie zawierają szczegółów potrzebnych do aktualizacji modelu odczytu

Niestety, jest to dość powszechny scenariusz.

Przykład: dodaję użytkownika do grupy, więc wysyłam polecenie addUserToGroup (id_użytkownika, groupId). To jest odbierane, obsługiwane przez program obsługi komend, zdarzenie userAddedToGroup jest tworzone, przechowywane i publikowane.

Teraz obsługa zdarzeń otrzymuje to zdarzenie i oba identyfikatory. Teraz pojawi się widok, który wyświetli listę wszystkich użytkowników z nazwami grup, w których się znajdują. Aby zaktualizować model odczytu dla tego widoku, potrzebujemy identyfikatora użytkownika (który mamy) i nazwy grupy (której nie robimy). t mamy, mamy tylko jego identyfikator).

Pytanie brzmi: jak obsłużyć ten scenariusz?

Obecnie cztery opcje przychodzą mi do głowy, wszystkie z ich specyficznych wad:

  1. Model odczytu zwraca się do domeny. => Zabronione, a nawet niemożliwe, ponieważ domena ma tylko zachowanie, nie ma (publicznego) stanu.

  2. Odczytany model odczytuje nazwę grupy z innej tabeli w przeczytanym modelu. => Działa, ale co, jeśli nie ma zgodnej tabeli?

  3. Dodaj potrzebne dane do wydarzenia. => Nie działa, ponieważ oznacza to, że musiałem aktualizować wszystkie poprzednie wydarzenia, i nie mogę przewidzieć, które dane będę potrzebował jednego dnia.

  4. Nie obsługuj zdarzenia za pomocą "zwykłej" obsługi zdarzeń, ale rozpocznij proces ETL w tle, który zajmuje się składnicą zdarzeń, tworzy potrzebne dane i zapisuje odczytany model. => Działa, ale wydaje mi się, że to trochę za dużo dla takiego prostego scenariusza.

Pytanie brzmi: Jak poprawnie poradzić sobie z tym scenariuszem?

Odpowiedz

5

Zdarzenia niekoniecznie reprezentują odwzorowanie "jeden do jednego" poleceń, które zainicjowały proces w pierwszej kolejności.Na przykład, jeśli masz polecenie:

SubmitPurchaseOrder 
    Shopping Cart Id 
    Shipping Address 
    Billing Address 

Powstały zdarzenie może wyglądać następująco:

PurchaseOrderSubmitted 
    Items (Id, Name, Amount, Price) 
    Shipping Address 
    Shipping Provider 
    Our Shipping Cost 
    Shipping Cost billed to Customer 
    Billing Address 
    VAT % 
    VAT Amount 
    First Time Customer 
    ... 

Zazwyczaj informacja jest dostępna dla modelu domeny (albo poprzez udostępnione przez polecenia lub jako znany stan wewnętrzny danego agregatu lub obliczany jako część przetwarzania).

Dodatkowo wydarzenie może zostać wzbogacone poprzez zapytanie do modelu odczytu lub nawet do innego BC (np. w celu pobrania rzeczywistego podatku VAT w zależności od stanu) podczas processi ng.

Prawidłowo zakładasz, że zdarzenia mogą (i prawdopodobnie będą) zmieniać się z czasem. Zasadniczo to nie ma znaczenia, jeśli używasz wersjonowania: Dodaj nowe wydarzenie (np. SubmitPurchaseOrderV2) i dodaj odpowiednią procedurę obsługi zdarzeń do wszystkich klas, które mają je zużywać. Nie trzeba zmieniać starego zdarzenia, może ono nadal być zużywane, ponieważ nie modyfikuje się interfejsu, można go rozszerzyć. To w praktyce sprowadza się do bardzo dobrego przykładu zasady Open/Closed.

+0

Okay, do tej pory, dostałem to ;-) To, czego jeszcze nie dostałem, to: Zakładam, że moje wydarzenie PurchaseOrderSubmitted _today_ nie zawiera podatku VAT. Teraz, szybko, do pewnego momentu w przyszłości, gdzie ja to robię. Oczywiście mogę stworzyć nowe wydarzenie, zasadniczo V2.0, które zawiera podatek VAT - ale to nie pomaga we wszystkich zamówieniach z przeszłości, prawda? Jak sobie z tym poradzić? –

+1

Możesz zmienić strukturę modelu i strukturę wydarzeń niezależnie od siebie. Gdy model zostanie rozszerzony o nową informację (np. VAT), obsługa starego zdarzenia pozostanie niezmieniona lub ustawi nową właściwość na wartość domyślną. Podobnie jak w przypadku dodawania nowej kolumny do tabeli bazy danych: Nowa kolumna musi mieć wartość zerową lub inną wartość domyślną dla wszystkich wpisów z odwołaniami. Za każdym razem, gdy zdarzenie zostanie odtworzone lub użyte do uwodnienia odczytanego modelu, nowe pole zostanie ustawione na dowolną wartość domyślną, jakiej potrzebujesz. –

+0

OK, dzięki, to ma sens :-)! –

7

Istnieją dwa typowe rozwiązania.

1) "Wzbogacanie wydarzeń" to miejsce, w którym rzeczywiście umieszczasz informacje o zdarzeniu, które odzwierciedla informacje, o których wspomniałeś, np. nazwa grupy. Robi to gdzieś pomiędzy prawidłowym modelowaniem domeny a oszustwami. Jeśli wiesz, na przykład, że nazwy grup się zmieniają, emitowanie nazwy w momencie zmiany nie jest złym pomysłem. Wyobraź sobie, że podczas tworzenia elementu zamówienia na wycenie lub fakturze chcesz emitować cenę towaru sprzedanego na zdarzeniu utworzonym na fakturze. Dzieje się tak, ponieważ musisz honorować tę cenę, nawet jeśli później się to zmieni.

2) Projektuj kilka strumieni jednocześnie. Napisz projektor, który ogląda informacje z różnych strumieni i łączy je razem. Możesz oglądać zdarzenia użytkowników i grup oraz użytkownika dodanego do wydarzenia grupowego. W zależności od kolejności zdarzeń w systemie, możesz wiedzieć, że użytkownik jest w grupie, zanim poznasz nazwę grupy, ale powinieneś poznać ogólne właściwości swojego sklepu z wydarzeniami, zanim zaczniesz.

+0

Dzięki, które wyjaśniły wiele :-)! –

+1

Nie jestem pewien, czy rozumiem # 2. czy prognoza przesyła zapytanie do strumienia lub po prostu czeka na nowe wydarzenie? Czy istnieje kluczowa praca, której mogę użyć do wyszukania tego procesu? Nauczyłem się "Wzbogacania wydarzeń", ale wydaje się to być złym sln. – Raif

+0

Projekcja jest zwykle komponentem, który uruchamia "ciągłe" czytanie jednego lub więcej strumieni podczas emitowania zdarzeń i rzutuje zmiany na odczytany model, na przykład relacyjną bazę danych. –

0

Opcja 2 byłaby w porządku, pytanie o "co do niezgodności w tabelach nazw grup" - "nie dotyczy". żadne dane nie powinny być usuwane, powinny zostać unieważnione po wydaniu poprzedniego zdarzenia (np. grupa usuwania). Na końcu wiersz w tabeli grup istnieje efektywnie i można bez problemu odczytać nazwę grupy. Jedynym widocznym problemem może być niespójność prędkości, ale jest to kolejna kwestia, zdarzenia powinny być uporządkowane bez względu na szybkość, z jaką są przetwarzane.

Powiązane problemy