DDD a referencje pomiędzy agregatami - C#+ EF Core

Odpowiedz Nowy wątek
2019-03-02 21:40
W2K
0

Cześć,

Mam pytanie bo w sumie nie do końca jestem pewny jak to poprawnie rozwiązać C# + EF Core
Sytuacja uproszczona: Mamy 2 agregaty - Item i Warehouse. Każdy z nich ma ExternalId (Guid) po to żeby identyfikować je na zewnątrz i Id bazodanowe. Item jest przypisany do Warehouse i podczas tworzenia Itemu musi być też znany Warehouse.

Czy podczas tworzenia (i updateu) itema powinno przekazywać się cały obiekt Warehouse, czy tylko jego Id (bazodanowe) ?
Np:

public Item(Warehouse warehouse,..)

czy

public Item(long warehouseId,..)

Podobnie z innymi operacjiami które wymagają tylko znajomości samego Warehousu a nie jego specyficznych właściwości.

Mam z tym problem bo z jednej strony czytam że agregat nie pownien przechowywać referencji do innego agregatu, a z drugiej przekazywanie Id bazodanowego do agregatu agregatu jest wyciekiem szczegółu implementacji (relacyjna baza jako sposób przechowywania) do domeny. Moim zdaniem lepszą opcją jest wersja pierwsza, ale poprawcie mnie jeśli się mylę.
Przekazywanie ExternalId :

public Item(Guid warehouseId,..)

nie wchodzi w grę bo w zasadzie nie rozwiązuje żadnego problemu - kluczami w bazie są id bazodanowe a nie ExternalId

edytowany 1x, ostatnio: W2K, 2019-03-02 21:41

Pozostało 580 znaków

2019-03-03 01:32
1

Warehouse powinien być aggregate root, a więc posiadać kolekcję itemów. Co za tym idzie każdy item musi posiadać ID warehouse'u do którego należy. W takim przypadku nie ma nic złego w wstrzykiwaniu warehouseId przez konstruktor item'u. Item nie powinien posiadać natomiast referencji do swojego aggregate root.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.

Pozostało 580 znaków

2019-03-03 02:00
W2K
0

@Aventus: Zarówno Warehouse jak i Item są osobnymi aggretage rootami. Przykład z konstruktorem jest średnio trafny. Zamiast konstruktora załóżmy metodę AssignToWarehouse po stronie Itema.
czy poprawne jest :

public void AssignToWarehouse(Warehouse warehouse,..)

czy :

public void AssignToWarehouse(long warehouseId,..)
Pokaż pozostałe 3 komentarze
A plakietkę z informacją o magazynie do którego należy przedmiot, przyklejasz na przedmiot czy na magazyn? - Arab 2019-03-03 11:06
Bardziej, by pasowała metoda PlacementAt(Place place) gdzie place to Value Object, który posiada numer magazynu, alejkę, pozycje na półce. - Arab 2019-03-03 11:09
Możesz to zrobić jeszcze ładniej, dodając specyfikację, wtedy masz Item -> ItemSpecyfication -> Location - Arab 2019-03-03 11:38
magazyn raczej wie co w nim siedzi, a magazynier zmienia w powiązanych z przedmiotem dokumentach tę informację w momencie przyjmowaniu dostawy - Miang 2019-03-03 12:23
Magazyn wie ? Raczej magazynier. Możesz sobie ewentualnie zrobić usługę ale nie widzę sensu. - Arab 2019-03-03 12:31

Pozostało 580 znaków

2019-03-03 11:35
1

Tak, uzytkownik wyzej jest trollem. Nie wdaje sie z nim w dyskusje, ale ciezko sie nie ustosunkowac jesli odnosi sie do moich wypowiedzi. Jest trollem ktory w dodatku bardzo malo wie a swoj brak wiedzy i racjonalnego myslenia probuje przerzucac na innych i siac ferment. Gdyby bylo inaczej, to ja bym byl wielokrotnie banowany a nie on. Miej to prosze na uwadze @W2K, bo moze Cie latwo wprowadzic w blad. Nawet jesli gdzies moze miec racje (co normalne) to nigdy nie mozesz byc pewny czy w konkretnej wypowiedzi tak jest, czy po prostu wcisnie Ci jakas glupote i bedziesz pozniej myslal ze to prawda. To tyle w tej kwesti, wiecej sie nie odnosze do tego dziwnego osobnika ktorego ciagnie do mnie jak nazgule do pierscienia :)

Wracajac do tematu, jesli item to rowniez aggregate root to tym bardziej nie powninen miec referencji do warehouse. Aggregate root wyznacza granice transakcyjnosci w obrebie swojego kontekstu i zapewnia spojnosc danych w tymze. Posiadanie referencji miedzy rootami bylo by pogwalceniem tej spojnosci, dla tego roots powinny miec do siebie "referencje" w postaci ID. Zmieniajac wiec warehouse item'u mozesz- tak jak wspomniales- miec po prostu jakas metode przyjmujaca ID nowego warehouse'u. Nie wiem o co codzi z tym external ID- warehouse jak i ID maja ID, nawet jesli w bazie uzywasz innych ID to w kontekscie domenowym to nie ma znaczenia. Tak wiec Twoj drugi przyklad jest wlasciwy. Zaznaczam jednak ze jest to ogolnie przyjeta praktyka a nie jakis odgorny dogmat. Nikt Cie nie powstrzyma przed wstrzyknieciem referencji obiektu, tym bardziej ja nie jestem zwolennikiem teorii "nie bo nie". Natomiast warto jednak zadac sobie pytania:

  • Czy musze miec referencje do obiektu warehouse w itemie?
  • Jesli tak to dla czego? Czy nie ryzykuje pogwalcenia transakcyjnosci miedzy tymi rootami?

W wiekszosci przypadkow nie powinno byc w ogole potrzeby posiadania referencji do innego root obiektu. W Twoim konkretnym przypadku tylko pomysl- niby jak jakas zmiana transakcyjna w obrebie itemu ma wplynac na warehouse? Przeciez nie zmienisz adresu/nazwy/cokolwiek warehouse'u zmieniajac cos w itemie ;)


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
Och, dla Aventus każdy kto się nie zgadza z jego opinią jest Trolem.... - Arab 2019-03-03 11:51

Pozostało 580 znaków

2019-03-03 12:19
3

@Arab @Aventus proszę się uspokoić. Nie zamierzam rozsądzać kto tu ma racje, bo przecież to walka sekciarzy z DDD, więc wiadomo ze nie ma tu żadnej logiki...
@W2K DDD=rak i nawet sami jego twórcy nie rozumieją pojęć i dogmatów które DDD promuje ;) Zalecam nie zawracać sobie głowy filozoficznymi dywagacjami, tylko pisać porządny kod :)


Na PW przyjmuje tylko (ciekawe!) zlecenia. Masz problem? Pisz na forum, nie do mnie.
Pokaż pozostałe 20 komentarzy
To co mi się nie podoba jest opisane tu http://blog.softio.pl/archiwu[...]ent-store-jak-to-dzia%C5%82a/ UncommitedEvents w aggregacie, wywoływanie Apply w komendach i koniecznośc robienia SaveChangesAsync po komendach to dla mnie jakis rak - powtarzanie kodu. Wszelkie przykłady DDD jakie widziałem tak mniej więcej robiły. - jarekr000000 2019-03-04 18:12
Pracowalem nad przykładem pozytywnym - chciałem pokazać jak to zrobić bez powtarzania kodu i niebezpieczeństwa, że się zapomni o np. Save, ale zabrakło mi czasu. Kiedyś będzie - ale nie w najbliższe 2 miesiace. - jarekr000000 2019-03-04 18:20
Pytanie całkiem serio- co Wy macie z tym rakiem? To rak, tamto rak. No co to ma być za argument, bez przesady ;) artykuł oczywiście przeczytam, natomiast nie za bardzo rozumiem co to za problem z powtarzalnością. Można zaimplementować np. Router który będzie zajmował się właśnie kierowaniem odpowiednich komand do agregatu (oraz pośrednim tworzeniem agregatu). Po zakończeniu operacji agregat może zostać zapisany, lub jego eventy zapisane itp. Ja nie widzę w tym nic złego. Mamy gotowy wzorzec do użycia, każdy kolejny programista może implementowac nowe funkcjonalności... - Aventus 2019-03-04 18:58
...stosując gotowe podejście. A jeśli chcemy to możemy zastosować coś co opisałem wyżej, czyli agregat bazowy. O już o wiele powtarzającego się kodu mamy mniej. - Aventus 2019-03-04 18:59
@Aventus Nie rozumiem o co ci chodzi z tym routerem i jaki to ma problem rozwiązać?. Chodzi ci o jakąś fabrykę...? @jarekr000000 Nie widzę również sensu w usuwaniu metody Aply w metodach, które otrzymują komendy. No chyba że jest to jedyna rzecz, którą wykonuje agregat :) - Gworys 2019-03-04 20:19

Pozostało 580 znaków

2019-03-03 12:46
2

@Shalom:
Trochę przesadziłeś, jak widzisz napisałem wyraźnie że nie będę się odnosił do jego wypowiedzi ale ciężko w ogóle nic nie napisać skoro mnie oczernia. Gdzie widzisz walkę dwóch sekciarzy? Ja tu widzę powracajacego trolla który się uczepił. Mi nie musisz wierzyć na słowo ale spytaj @somekind i @Patryk27. Także nazywanie mnie sekciarzem mogłeś sobie darować... Dzięki za zrownywanie mnie z trollem po tych kilku latach na forum, a to wszystko bo masz swoje negatywne zdanie na temat DDD. Nie spodziewałem się czegoś takiego po wydawało by się szanowanym tutaj moderatorze. Aż się odechciewa tutaj udzielać...


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 1x, ostatnio: Aventus, 2019-03-03 12:47
Pokaż pozostałe 12 komentarzy
W dodatku to chyba jakiś mój psychofan-hejter bo gdzie się nadazy okazja to się przyczepia do mnie, ostatnio nawet (na poprzednim koncie, a jakże) miał w stopce moje wypowiedzi. Z kimś takim nie ma możliwości polemizowania. - Aventus 2019-03-03 18:08
Natomiast chyba logicznym jest ze jeśli gdzieś się wypowiadam, chce komuś pomóc po czym pojawia się ten osobnik oczerniający mnie to muszę się jakoś do tego odnieść żeby osoba której staram się pomóc rozumiała o co chodzi. Jeśli będę siedział cicho to będzie to wyglądało jakbym się zgadzał z oskarżeniami- nie znam się, gadam głupoty, nie mam doświadczenia etc. Raz jeszcze podkreślam- podejmowałem próby merytorycznej dyskusji, na nic się to zdało. - Aventus 2019-03-03 18:11
No ale chyba na nic moje komentarze jeśli jeden moderator nazywa mnie seksiarzem nie znając kontekstu (to tak jak ja bym z tyłka pisał komentarze że shalom to tylko crudy pisze doświadczonym programistom w cernie) a drugi moderator na forum zachęca do polemiki... z trollem. Od kiedy to z trollami należy nawiązywać jakąkolwiek dyskusję? - Aventus 2019-03-03 18:14
Aha, @aurel co to wulgaryzmów to ten troll w komentarzach nazywał kogoś idiotą (nie pamiętam nazwy użytkownika). W związku z tym zgłosiłem post (bo komentarzy się nie da). Widocznie zanim to zobaczyłaś to obraźliwe komentarze zostały usunięte. - Aventus 2019-03-03 18:20
@Aventus, no spoko, nie rozpoznałam trolla, wulgaryzmów nie widziałam, więc byłam zdziwiona raportami. - aurel 2019-03-03 22:15

Pozostało 580 znaków

2019-03-03 23:38
5

Przepraszam, że się wtryniam w wątek, żeby nie było, scruma nie cierpię (tego dobrego, złego, średniego i w ogóle żadnego). Ale DDD zrobione pod projekt (a nie pod książkę z roku X), z Event Stormingiem (czekam aż tu zaraz ktoś pomiesza nazewnictwa i mi odpowie na coś innego, co pojawia się po słowie Event) to IMO zupełnie inna para kaloszy.

Zresztą, co ja tu ten tego, jak ktoś uważa, że to rak, to chętnie poznam jego proces rozumowania i projektowania architektury złożonej z większej ilości elementów niż 3 (mikroserwisów, monolitów, stereolitów czy czego tam) i dochodzenia do ewentualnych edge kejsów, zanim wystąpią one na poziomie pisania porządnego kodu, czyli wtedy, kiedy będzie już dawno "pozamiatane" i inwestorzy/klienci niestety nie podzielą naszego entuzjazmu, że przecież o to mamy clean code, lintery na zielono, good practik, a że koszty przepisania sporej części projektu z nienacka strzeliły nas obuchem to taki skutek uboczny.[1]

[1]Tak, tak, pamiętam - należy pisać porządny kod bez błędów... związanych z architekturą.

Pokaż pozostałe 6 komentarzy
@TurkucPodjadek: brałem udział, tylko nie nazywało się to "event stormingiem", tylko zwyczajnie "warsztaty z klientem" :-) Nazywanie czegoś, co znane jest ludzkości od dawna, nowym terminem i sprzedawanie jako "nowe-lepsze", to nie marketing? Zerknij np. do RUPa, gdzie masz dyscyplinę pt. "modelowanie biznesowe". Mam wrażenie, że niektórzy programiści dzięki DDD odkryli, że zrozumienie perspektywy biznesowej jest bardzo istotne przy tworzeniu oprogramowania, które ma ten biznes wspierać. Bezdyskusyjnie pozytywny efekt :-) - yarel 2019-03-09 14:57
@yarel: nie wiem co to były za warsztaty w Twoim przypadku, ale często event storming myli się z brain storming, a to nieco inne rzeczy w tym przypadku. Ja wiem, że DDD to nic nowego, ale ma więcej sensu niż (A|H)DD. - TurkucPodjadek 2019-03-09 15:11
@yarel: czyli podczas tych warsztatów definiowaliscie eventy które następnie są używane do integracji między kontekstami, tak? - Aventus 2019-03-09 15:24
@Aventus: nie definiowaliśmy eventów, tylko opisywali procesy biznesowe w notacji BPMN, więc zdarzenia były ściśle biznesowe typu "Zamówienia złożone", "Płatność zaksięgowana", "Towar wysłany" itd. + dane przewijające się w ramach procesu, bez jakichkolwiek odnośników do technikaliów typu "klasa", "integracja", "kontekst", "transakcja". Później takie procesy były implementowane w oparciu o Camundę. Taki proces (z tego co rozumiem DDD) to odpowiednik "sagi". Dlatego na DDD patrzę jako na "znane-ale-sprzedawane-pod-inną-nazwą" ;) - yarel 2019-03-09 19:19
Ok, a event storming wyraźnie podkreśla znaczenie definiowania eventów. Nie rozumiem w sumie o co chodzi, jedno nie wyklucza drugiego bo to prawie ten sam proces. To żaden "chłyt", po prostu wyraźne zaznaczenie co chce się osiągnąć. Nikt nie twierdzi że sesje z ludźmi z biznesu to nowość którą zawdzięczamy DDD. Tak samo jak chociażby taki kanban używany już 50 lat temu przez Toyote- przecież nikt nie twierdzi że zostało to dopiero co wymyślone przez świat IT. - Aventus 2019-03-09 21:18

Pozostało 580 znaków

2019-03-04 02:28
1

Warehouse powinien być aggregate root, a więc posiadać kolekcję itemów. Co za tym idzie każdy item musi posiadać ID warehouse'u do którego należy.

Jak to posiadać kolekcję itemów.?
Agregat root to nie jest żadną kolekcją na itemy. To aggregat Warehouse i aggregat Item ma posiadać referencje do jednego id w tym wypadku warehouseId... Mówisz tak, że nie wiadomo czy ci chodzi o encje czy o co?

W takim przypadku nie ma nic złego w wstrzykiwaniu warehouseId przez konstruktor item'u

Mówisz o przekazaniu zależności, a nie o wstrzykiwaniu. Wstrzykiwanie odbywa się na poziomie komponentów a nie przekazaniu wartości w metodzie.

Item nie powinien posiadać natomiast referencji do swojego aggregate root.

Czyli item ma posiadać warehouseId, ale nie może mieć referencji do swojego aggregate root....?

Jakiego swojego agregatu nic z tego nie rozumiem. Może ty mylisz założenia modelu...?
Przecież ewidentnie Item jest Aggregatem i Warehouse również
Ty chyba nie odróżniasz Aggregatu od Value Objectu albo Encji.
Bardzo proszę czy mógł byś się wyrazić jaśniej.?


Unhandled Exception: System.MissingMethodException: Constructor on type 'System.Exception' not found.
Mówisz o przekazaniu zależności, a nie o wstrzykiwaniu. Przecież sama książka mówi o tym, że nie wolno nic wstrzykiwać do aggregatu... Aventus chyba jej nie czytał :D - CioCio 2019-03-04 10:57
sama książka mówi o tym :D no jak książka mówi to wiadomo że to prawda objawiona :D - Shalom 2019-03-04 12:15
Czyli rozumiem, że obiekty ze wzorca Domain Model ustawiasz za pomocą "Injector'a".? Acha no spoko. Tu już nie chodzi o same DDD tylko o podstawy wzorców jak Domain Model i Dependency Injection. - CioCio 2019-03-04 12:32
Widzisz jakiś sens w wypowiadaniu się na temat książki, której się nie przeczytało.? - CioCio 2019-03-04 12:54

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0