Zaczynam od DDD i rozumiem, że do zapewnienia spójności ponadnarodowej używa się zagregowanych korzeni. Nie powinniśmy modyfikować wielu agregatów w jednej usłudze aplikacji.
Chciałbym jednak wiedzieć, jak poradzić sobie z następującą sytuacją.
Mam zagregowany katalog główny o nazwie Produkty.
Istnieje również zagregowany katalog główny o nazwie Grupa.
Oba mają identyfikatory i mogą być edytowane niezależnie.
Wiele produktów może wskazywać na tę samą grupę.
Mam usługę aplikacji, która może zmienić grupę produktów:
ProductService.ChangeProductGroup(string productId, string groupId)
- Grupa kontrolna istnieje
- Pobierz produkt z repozytorium
- Ustaw jego grupę
- Napisz produkt z powrotem do repozytorium
Mam również usługę aplikacji, w której grupę można usunąć:
GroupService.DeleteGroup(string groupId)
1. Pobierz produkty z repozytorium, dla którego groupId jest ustawiony na podany groupId, upewnij się, że liczba wynosi 0 lub przerwij 2. Usuń grupę z repozytorium grup 3. Zapisz zmiany
Moje pytanie dotyczy następującego scenariusza, co by się stało, gdyby:
W ProductService.ChangeProductGroup sprawdzamy, czy grupa istnieje (tak jest), a następnie tuż po tym sprawdzeniu oddzielny użytkownik usuwa productGroup (za pośrednictwem innego GroupService.DeleteGroup). W takim przypadku umieściliśmy odniesienie do produktu, który właśnie został usunięty?
Czy to wada mojego projektu polegająca na tym, że powinienem używać innego projektu domeny (w razie potrzeby dodając dodatkowe elementy), czy też musiałbym używać transakcji?
źródło
Dlaczego nie przechowujesz identyfikatorów produktów w podmiocie Grupy? W ten sposób masz do czynienia tylko z jednym agregatem, który ułatwi ci wszystko.
Będziesz wtedy musiał zaimplementować pewien rodzaj wzorca współbieżności, np. Jeśli wybierzesz optymistyczną współbieżność, po prostu dodaj właściwość wersji do encji Grupy i wyrzuć wyjątek, jeśli wersje nie pasują podczas aktualizacji, tj.
Dodaj produkt do grupy
Wiele ORM ma optymistyczną współbieżność wbudowaną za pomocą identyfikatorów wersji lub znaczników czasu, ale łatwo jest stworzyć własną. Oto dobry post na temat tego, jak to zrobić w Nhibernate http://ayende.com/blog/3946/nhibernate-mapping-concurrency .
źródło
Chociaż transakcje mogą pomóc, istnieje inny sposób, zwłaszcza jeśli Twój scenariusz jest ograniczony tylko do kilku przypadków.
Możesz włączyć kontrole do zapytań, które powodują mutacje, skutecznie czyniąc każdą parę kontroli i mutacji operacją atomową.
Wewnętrzne zapytanie aktualizujące produkt dołącza do grupy (nowo przywołanej). Powoduje to, że nic nie aktualizuje, jeśli ta grupa zniknie.
Kwerenda usuwająca grupę dołącza do wszystkich produktów do niej wskazujących i ma dodatkowy warunek, że (dowolna kolumna) wynik łączenia musi być zerowy. Powoduje to, że nic nie usuwa, jeśli wskazują na to jakiekolwiek produkty.
Zapytania zwracają liczbę wierszy, które pasowały lub zostały zaktualizowane. Jeśli wynik wynosi 0, oznacza to, że przegrałeś wyścig i nic nie zrobiłeś. Może zgłaszać wyjątek, a warstwa aplikacji może obsłużyć to, co chce, na przykład próbując od początku.
źródło