DDD i obiekty wartości. Czy zmienne obiekty wartości są dobrym kandydatem na Non Aggr. Root Entity?

9

Oto mały problem

Posiadaj obiekt z obiektem wartości. Żaden problem. Zamieniam obiekt wartości na nowy, a następnie nhibernate wstawia nową wartość i osierocam starą, a następnie usuwa ją. Ok, to jest problem.

Ubezpieczony jest moją jednostką w mojej domenie. Ma zbiór adresów (obiekty wartości). Jednym z adresów jest MailingAddress. Kiedy chcemy zaktualizować adres pocztowy, powiedzmy, że kod pocztowy był nieprawidłowy, zgodnie z doktryną pana Evansa, musimy zastąpić stary obiekt nowym, ponieważ jest niezmienny (obiekt wartości prawda?).

Ale nie chcemy usuwać tego wiersza, ponieważ PK tego adresu to FK w tabeli MailingHistory. Tak więc, postępując zgodnie z doktryną pana Evansa, jesteśmy tutaj w dużym stopniu popieprzeni. Chyba, że ​​utworzę moje Adresy, więc nie muszę go „zastępować” i po prostu aktualizować członka kodu pocztowego, jak za starych dobrych czasów.

Co byś mi zasugerował w tej sprawie? Z mojego punktu widzenia ValueObjects są użyteczne tylko wtedy, gdy chcesz obudować grupę kolumn tabeli bazy danych (komponent w nhibernate). Wszystko, co ma identyfikator trwałości w bazie danych, lepiej jest uczynić z niego Entity (niekoniecznie zagregowany katalog główny), abyś mógł aktualizować jego elementy bez odtwarzania całego wykresu obiektów, szczególnie jeśli jest to obiekt głęboko zagnieżdżony.

Zgadzasz się? Czy Mr. Evans może mieć obiekt o zmiennej wartości? A może obiekt o zmiennej wartości jest kandydatem na byt?

Dzięki

Pepito Fernandez
źródło
2
Czy istnieje coś takiego jak „obiekt o zmiennej wartości”? Zawsze miałem wrażenie, że obiekty są niezmienne.
herby
@herby Wydaje mi się, że możesz mieć w kodzie zmienny obiekt reprezentujący obiekt wartości DDD, ale musisz wziąć pod uwagę, że po zmutowaniu obiekt nie odnosi się już do tego samego logicznego obiektu wartości DDD, ale do nowego. Może to być pożądane, ale jest to przepis na nieporozumienia - tworzenie wartościowych obiektów niezmiennych w kodzie jest inteligentną konwencją.
MattDavey,

Odpowiedzi:

8

Wszystko, co ma tożsamość, powinno być bytem, ​​a wszystko, co nie ma tożsamości, jest prostą wartością, a więc przedmiotem wartości.

Cytując Martina Fowlera (który z kolei wymienia Erica Evansa)

  • Podmiot: Obiekty, które mają odrębną tożsamość, która biegnie w czasie i mają różne reprezentacje. Słyszysz także te nazywane „obiektami odniesienia”.
  • Obiekt wartości: obiekty, które mają znaczenie, mają tylko kombinację swoich atrybutów.

Powód, dla którego twój adres jest obiektem wartości:

Jeśli twój adres jest zmienny, prawdopodobnie zepsujesz swoją historię mailingową. Na przykład, jeśli wysyłasz przedmioty do klienta, nie możesz być pewien, na który adres faktycznie wysłałeś coś w przeszłości, jeśli adres, do którego odnosi się twoja tabela MailingHistory, został zmieniony.

Wpis MailingHistory Wysłaliśmy A764 na adres 657, co może oznaczać, że wysłaliśmy wczoraj artykuł A764 do Bostonu, a jutro wysłaliśmy artykuł A764 do Nowego Jorku .

Jeśli adres pocztowy musi zostać zmieniony, nie trzeba usuwać starego. Zatrzymaj go i oznacz jako nieaktywny , a nowy jako aktywny .


Oczywiście możesz traktować swój adres jako byt, ale tylko podczas jego aktualizacji nie zmieniłoby to rzeczywistego miejsca, do którego odnosi się adres, a zatem pozwala jedynie na poprawienie literówek.

Jeśli jesteś pewien, że możesz to zapewnić, możliwe będzie użycie Jednostki.


Ale najlepszym rozwiązaniem IMHO jest nie odwoływanie się do adresu Entity w historii mailingu, ale raczej zapisanie określonego adresu bezpośrednio w tabeli historii mailingu (w zasadzie kopiowanie danych adresu).

W ten sposób zawsze wiesz, gdzie wysłałeś swoje rzeczy (lub cokolwiek, co wysyłasz), a ponieważ użyjesz zmiennej Jednostki, twoja tablica adresów nie będzie zagracona.

Pracowałem z / na kilku systemach ERP i prawie wszystkie z nich stosowały to podejście.

Będziesz miał nadmiarowość w swojej bazie danych, ale jest to najbardziej pragmatyczny sposób IMHO.

Leniwiec
źródło
Jest to prawdopodobnie najbardziej wolne od bólu rozwiązanie. Tylko jeśli oczekujesz, że przyszłe kanały komunikacji będą wymagały dodatkowych kolumn, a twoja baza danych jest zbyt duża ALTER, użycie encji w osobnych tabelach może być konieczne. To z kolei wymaga strategii takich jak „zawsze dołączaj do najnowszego adresu / telefonu / e-maila” w swoich SELECTzapytaniach, które są trudne do utrzymania i wydajne. Uprość to, jeśli to w ogóle możliwe.
Timo
@ Timo „zawsze dołączaj do najnowszego adresu / telefonu / e-maila” nie jest trudne, jeśli trochę denormalizujesz swoje dane, po prostu dodając activeflagę. Oczywiście musisz upewnić się, że zawsze używasz and active = truew swoich połączeniach, aktualizujesz flagę i dodajesz ograniczenie do swojej tabeli, aby np. Tylko jeden e-mail dla każdego klienta mógł ustawić tę flagę na wartość true.
lenistwo
Wprowadza to problem dezaktywacji poprzedniego. Jeśli zastąpiłeś „bieżący” obiekt adresu w kodzie i przejdziesz do kodu dostępu do danych, nie będzie wiedział (1), czy jest nowy, czy (2) jaki potencjalny stary jeden był. Tak więc każda operacja składowania będzie musiała zrobić coś skomplikowanego, np. „Najpierw idź i dezaktywuj wszystkie powiązane adresy w bazie danych”, a następnie zapisz bieżący za pomocą active=true. Nie to nazwałbym prostym i właśnie dlatego podoba mi się twoje rozwiązanie.
Timo
2

Widzę 2 rzeczy:

  1. Czy zmiana kodu pocztowego może wpłynąć na zapis historii? Myślę, że logiczne byłoby, gdyby rekord historii wskazywał na stary, niezmieniony adres, więc wiesz, że wysyłasz go na zły adres.

  2. W momencie, gdy MailingHistory ma FK na adres, adres przestał być obiektem wartości i stał się bytem. Obiekty wartości nie mają tożsamości, co pozwala innym podmiotom odwoływać się do tej tożsamości. Możesz mieć adresy w jednej tabeli z innymi tabelami do niego wskazującymi, ale jedynym efektem jest oszczędność miejsca. Z punktu widzenia domeny, jeśli dwa podmioty mają odwołanie do tego samego typu obiektu wartości, to nie udostępniają żadnego rodzaju informacji.

Euforyk
źródło
2

IMO obiektem adresowym jest byt w Twojej domenie. Jest współdzielony przez wiele podmiotów, ma własną tożsamość i jest unikalny w całym systemie.

Evans mówi:

Obiekt zdefiniowany przede wszystkim przez swoją tożsamość nazywa się bytem.

margabit
źródło
Według mnie tożsamości domenowe nie mają nic wspólnego z trwałością tożsamości. Według książki pana Evana.
Pepito Fernandez,
Masz rację. Edytuję swoją odpowiedź. Mam na myśli to, że obiekt Adres ma znaczenie w tej konkretnej domenie, jest unikalny. IMO klucz obcy i klucz podstawowy to znak, że tak naprawdę jest to unikalny obiekt w całej domenie, więc ma tożsamość.
margabit
1
„obiekt adresowy ... ma swoją tożsamość” - który atrybut adresu jednoznacznie go identyfikuje? Żaden pojedynczy atrybut adresu nie jest unikalny, ale kombinacja atrybutów służy jako tożsamość. To jest właśnie definicja obiektu wartości
MattDavey
@MattDavey: to dobry wniosek, ale jestem zdezorientowany, gdy Tony mówi: „nie chcemy usuwać tego wiersza, ponieważ PK tego adresu to FK w tabeli MailingHistory”. Oznacza to dla mnie, że obiekt Adres ma również znaczenie poza Zagregowanym „Ubezpieczonym”. Co wskazuje mi, że obiekt „Adres” nie powinien być obiektem ValueObject. Co myślisz?
margabit
Czy możemy powiedzieć, że obiekty wartości zawsze byłyby w całości własnością UML? Ponadto obiekt wartości nie miałby sensu bez jego obiektu nadrzędnego i nie mógłby być dzielony między rodzicami?
Sudarshan