Rozwiązanie problemu polegającego na tym, że klucze podstawowe nie są częścią domeny biznesowej

25

W prawie wszystkich okolicznościach klucze podstawowe nie są częścią domeny biznesowej. Pewnie, możesz mieć pewne ważne obiekty z unikalnymi indeksami ( UserNamedla użytkowników lub OrderNumberzamówień), ale w większości przypadków nie ma potrzeby jawnego identyfikowania obiektów domeny za pomocą pojedynczej wartości lub zestawu wartości, dla kogokolwiek, ale może użytkownik administracyjny. Nawet w tych wyjątkowych przypadkach, szczególnie jeśli używasz globalnych unikalnych identyfikatorów (GUID) , polubisz lub zechcesz użyć alternatywnego klucza zamiast ujawniać sam klucz podstawowy.

Tak więc, jeśli moje rozumienie projektowania opartego na domenie jest dokładne, klucze podstawowe nie muszą, a zatem nie powinny być odsłonięte, i dobra gra. Są brzydkie i dręczą mój styl. Ale jeśli zdecydujemy się nie włączać kluczy podstawowych do modelu domeny, będą miały konsekwencje:

  1. Naiwnie obiekty przesyłania danych (DTO), które pochodzą wyłącznie z kombinacji modeli domen, nie będą miały kluczy podstawowych
  2. Przychodzące DTO nie będą miały klucza podstawowego

Czy można więc powiedzieć, że jeśli naprawdę chcesz zachować czystość i wyeliminować klucze podstawowe w modelu domeny, powinieneś być przygotowany na to, że będziesz w stanie obsłużyć każde żądanie w zakresie unikalnych indeksów tego klucza podstawowego?

Innymi słowy, które z poniższych rozwiązań jest właściwe podejście do identyfikowania poszczególnych obiektów po usunięciu PK w modelach domenowych?

  1. Umiejętność rozpoznawania obiektów, z którymi musisz się zmierzyć, na podstawie innych atrybutów
  2. Odzyskiwanie klucza podstawowego z powrotem w DTO; tj. eliminując PK podczas mapowania z trwałości do domeny, a następnie rekombinując PK przy mapowaniu z domeny do DTO?

EDYCJA: Zróbmy to konkretnie.

Powiedzieć moim modelu domeny VoIPProvider, która obejmuje obszary takie jak Name, Description, URL, jak również odnośników podoba ProviderType, PhysicalAddressi Transactions.

Powiedzmy teraz, że chcę zbudować usługę internetową, która pozwoli uprzywilejowanym użytkownikom zarządzać VoIPProviders.

Być może przyjazny dla użytkownika identyfikator jest w tym przypadku bezużyteczny; w końcu dostawcy VoIP są firmami, których nazwy są zwykle wyraźne w sensie komputerowym, a nawet wystarczająco wyraźne w sensie ludzkim ze względów biznesowych. Być może wystarczy powiedzieć, że unikat VoIPProviderjest całkowicie zdeterminowany (Name, URL). Powiedzmy teraz, że potrzebuję metody PUT api/providers/voip, aby uprzywilejowani użytkownicy mogli aktualizować VoIPdostawców. Wysyłają VoIPProviderDTO, który zawiera wiele, ale nie wszystkie pola z VoIPProvider, w tym niektóre potencjalnie spłaszczające. Nie umiem jednak czytać w ich myślach i nadal muszą mi powiedzieć, o którym dostawcy mówimy.

Wygląda na to, że mam 2 (może 3) opcje:

  1. Uwzględnij klucz podstawowy lub klucz alternatywny w moim modelu domeny i wyślij go do DTO i odwrotnie
  2. Zidentyfikuj dostawcę, na którym nam zależy, za pomocą unikalnego indeksu, np (Name, Url)
  3. Wprowadź jakiś rodzaj obiektu pośredniego, który zawsze może mapować między warstwą trwałości, domeną i DTO w sposób, który nie ujawnia szczegółów implementacji dotyczących warstwy trwałości - powiedzmy, wprowadzając tymczasowy identyfikator w pamięci podczas przechodzenia z domeny do DTO iz powrotem,
tacos_tacos_tacos
źródło
1
Punkt do przemyślenia: często komunikacja z ekspertami domeny jest zubożona, gdy używane są zastępcze PK, gdy istnieje dobry klucz biznesowy. Wygląda na to, że w końcu pracujemy dla frameworka ORM, a nie na odwrót.
Tulains Córdova
@ user61852 dobrze, niezależnie od ORM, nawet jeśli naprawdę niski poziom, nadal potrzebujesz klucza podstawowego w implementacji warstwy bazy danych. Zgadzam się więc, że zastępcze PK daje przewagę nad faktycznym PK używanym przez konkretny mechanizm trwałości, ale jeśli ten PK naprawdę reprezentuje znaczący obiekt biznesowy, jest on koniecznie unikalny i dlatego ma przynajmniej jedną unikalną właściwość biznesową to nie?
tacos_tacos_tacos
1
Wszystkie zalety surogatów są związane z komputerem i nie dotyczą człowieka.
Tulains Córdova
2
@ user61852: Zgadzam się w 100% (czy napisałem coś innego?). Jako środka komunikacji użyj „klucza biznesowego”. Dodaj unikalne ograniczenia dla dowolnego klucza biznesowego. Ale unikaj używania kluczy biznesowych do faktycznej implementacji odniesień do bazy danych.
Doc Brown
2
klucze biznesowe są wiecznie unikalne - dopóki nie są. Jeśli używasz kluczy biznesowych jako podstawowych, gdy tak się dzieje, zmiana reguł biznesowych psuje więcej rzeczy.
psr

Odpowiedzi:

31

W ten sposób rozwiązujemy ten problem (od ponad 15 lat, kiedy nie wynaleziono nawet terminu „projektowanie oparte na domenie”):

  • podczas mapowania modelu domeny na implementację bazy danych lub modelu klasy w określonym języku programowania, masz prostą, spójną regułę, taką jak „dla każdego obiektu domeny zamapowanego na tabelę relacyjną, kluczem podstawowym jest„ TablenameID ”.
  • ten klucz podstawowy jest całkowicie sztuczny, ma zawsze ten sam typ i nie ma znaczenia biznesowego - tylko klucz zastępczy
  • „wersja graficzna” modelu domeny (ta, której używasz do rozmowy ze specjalistami ds. domeny), nie zawiera kluczy podstawowych. Nie udostępniasz ich bezpośrednio ekspertom (ale udostępniasz je każdemu, kto faktycznie implementuje kod dla systemu).

Kiedy więc potrzebujesz klucza podstawowego do celów technicznych (takich jak mapowanie relacji do bazy danych), masz go dostępny, ale dopóki nie chcesz go „zobaczyć”, zmień poziom abstrakcji na „model ekspertów domeny „. I nie musisz utrzymywać „dwóch modeli” (jednego z PK i jednego bez); zamiast tego utrzymuj tylko model bez PK i użyj generatora kodu, aby utworzyć DDL dla swojej bazy danych, który automatycznie doda PK zgodnie z regułami mapowania.

Pamiętaj, że nie zabrania to dodawania żadnych „kluczy biznesowych”, takich jak dodatkowy „OrderNumber”, oprócz surogatu OrderID. Technicznie te klucze biznesowe stają się kluczami alternatywnymi podczas mapowania do bazy danych. Po prostu unikaj używania ich do tworzenia odniesień do innych tabel, zawsze preferuj używanie kluczy zastępczych, jeśli to możliwe, to znacznie ułatwi sprawę.

Komentarz: użycie klucza zastępczego do identyfikacji rekordów nie jest operacją związaną z biznesem, jest operacją czysto techniczną. Aby to wyjaśnić, spójrz na swój przykład: dopóki nie zdefiniujesz dodatkowych unikalnych ograniczeń, możliwe byłoby posiadanie dwóch obiektów VoIPProvider o tej samej kombinacji (nazwa, adres URL), ale różnych VoIPProviderID.

Doktor Brown
źródło
A co z etapem pobierania obiektu domeny ze zwróconego obiektu trwałości (encja, model wiersza tabeli lub cokolwiek innego), przechodzenia do DTO, przyjmowania go z powrotem i powrotu do trwałości? Czy odbywa się to tylko za pomocą klucza zastępczego (tj. Zorientowanej na biznes definicji wyjątkowości), która wymaga rozwiązania każdej operacji trwałości?
tacos_tacos_tacos
1
@tacos_tacos_tacos: trzymajmy się twojego przykładu VoIPProvider. Dodałbym „VoIPProviderID” do twojego DTO, przynajmniej po „stronie implementacyjnej” (jeśli masz także wersję graficzną dla ekspertów w dziedzinie, prawdopodobnie nie pokazałbym jej tam). Do celów aktualizacji standardowym sposobem identyfikacji konkretnego VoIPProvider powinien być „VoIPProviderID” pobrany podczas pobierania danych z bazy danych. Jeśli użytkownicy Twojego interfejsu API wolą identyfikację według (nazwa, adres URL), podaj to dodatkowo. ...
Doc Brown
... a jeśli wydajność wydaje się rzeczywistym, mierzalnym problemem, możesz również rozważyć buforowanie mapowania (nazwa, adres URL) na VoIPProviderID. Ale nie zalecałbym przedwczesnego wdrożenia takiej optymalizacji.
Doc Brown
1
Naturalne klucze czasami wydają się naprawdę atrakcyjne, ale zbyt łatwo je spalić (np. „Ups, teraz mam wielu najemców i to już nie jest wyjątkowe”).
Casey
1
@corsiKa: w kontekście tego, o co poprosił PO, zdecydowanie zalecałbym posiadanie czysto automatycznie generowanego klucza „OrderID” (który nie jest drukowany na żadnym pokwitowaniu, ale służy tylko do wewnętrznych czynności, takich jak odniesienia do bazy danych), oraz osobny klucz biznesowy „OrderNumber” (który może na przykład zawierać coś takiego jak bieżący rok, którego można użyć do sortowania i filtrowania, który można później zmienić / poprawić i który można wydrukować na paragonach). OP poprosił o „Domain Driven Design”, „OrderNumber” jest częścią modelu domeny, a „OrderID” to tylko szczegół implementacji.
Doc Brown
4

Musisz być w stanie zidentyfikować wiele obiektów za pomocą jakiegoś unikalnego indeksu i nie jest to tym, co jest kluczem podstawowym (lub przynajmniej sugeruje, że jeden jest obecny).

Dostępne są unikalne indeksy, dzięki czemu można dodatkowo ograniczyć schemat DB, a nie jako hurtowy zamiennik PK. Jeśli nie ujawniasz PK, ponieważ są brzydkie, ale zamiast tego wystawiasz unikalny klucz ... tak naprawdę nie robisz nic innego. (Zakładam, że nie dostaniesz tutaj PK i kolumny tożsamości?)

gbjbaanb
źródło
Kiedy chcę wykonać operację obejmującą określoną instancję obiektu domeny, która jest utrwalona, ​​muszę mieć możliwość wyraźnego włączenia do DTO (za pomocą jakiegoś klucza, podstawowego lub alternatywnego przyjaznego dla użytkownika identyfikatora, który jest unikalny do tej tabeli i równie dobrze może być indeksem na stole) lub pośrednio (poprzez pewną kombinację pól, których wartości jednoznacznie identyfikują konkretny rekord) ... a ponadto, w sensie praktycznym, musiałbym wysłać w DTO jakąś formę śledzenia zmian, gdybym zrobił to w inny sposób (OriginalVal vs. NewVal dla wszystkich pól identyfikujących rekord), nie?
tacos_tacos_tacos
czy jawne v niejawne pytanie nie ma tej samej różnicy? Możesz mieć PK, który obejmuje wiele kolumn, podobnie jak unikalny indeks. Nie widzę żadnej różnicy między nimi dla twoich celów.
gbjbaanb
Jasne, na przykład możemy mieć PK w wielu kolumnach. Ale dla mnie to przecieka coś o databaswe (pamięć), która nie powinna mieć NIC wspólnego z sercem i duszą, bytem biznesowym. Jeśli zdarzy się, że jakaś krotka pól jednostek biznesowych obejmuje PK dla bazy danych, to świetnie. Ale niekoniecznie powinno być odwrotnie, prawda?
tacos_tacos_tacos
Przemyślasz to. Unikalny indeks jest tak samo artefaktem schematu DB, jak PK. Pomyśl o tym w ten sposób - PK jest tylko pierwszym (lub podstawowym) unikalnym indeksem. jest to „specjalne”, ponieważ na ogół potrzebujesz tylko 1 takiego indeksu.
gbjbaanb
To prawda, ale każdy znaczący obiekt domeny powinien być identyfikowalny ściśle z co najmniej jednego z jego pól biznesowych, prawda? Fakt, że definiuje to indeks w DB, jest bardziej ze względów wydajnościowych niż do łatwego zapytania do DB ... Wolałbym jednokolumnową PK niż 6-kolumnowy unikalny indeks i naprawdę służą one innym celom - PK (lub indeks z małą liczbą pól) jest również dostępny dla wygody DBA / DBD, prawda?
tacos_tacos_tacos
4

Bez kluczy podstawowych w interfejsie nie ma łatwego sposobu, aby backend wiedział, co wysyłasz. Aby to naprawić, potrzebowałbyś mnóstwo dodatkowej pracy podczas analizowania danych, co obniżyłoby wydajność i prawdopodobnie zająłoby więcej czasu i byłoby bardziej brzydkie niż dołączanie klucza do każdego elementu.

Na przykład załóżmy, że chcę edytować wiadomość w aplikacji; skąd aplikacja miałaby wiedzieć, którą wiadomość chcę edytować bez dołączonego klucza podstawowego? Edycja obiektów odbywa się cały czas, a robienie tego bez kluczy jest prawie niemożliwe. Ale jeśli masz obiekty, które nie powinny być edytowane, pomiń klucz, jeśli uważasz, że to rozprasza, ale posiadanie kluczy podstawowych może tutaj poprawić wydajność.

Johan
źródło
Cóż, wiadomość jest przykład skrajny, ale nawet wtedy wiedziałby MessageSender, MessageRecipient, TimeSent- które powinny być unikalne.
tacos_tacos_tacos
1
@tacos_tacos_tacos, to jak tworzysz FK do innych tabel? Powinien to być MessageSenderId, który prawdopodobnie odwzorowuje tabelę użytkowników na UserId. Nie chcesz używać nazwy użytkownika jako klucza między tabelami, ponieważ może to się zmienić i stać się koszmarem konserwacji. Dlatego zazwyczaj łączysz tabele tylko przy użyciu kluczy podstawowych, a nie innej kolumny (są oczywiście wyjątki). Ta struktura db nadal musi być wymuszona. Teraz możesz zawsze przejść do modelu CQRS dla swojej aplikacji ... w takim przypadku reguły się zmieniają. Zwłaszcza jeśli korzystasz również ze Sourcingu wydarzeń.
CaffGeek
4

Powodem, dla którego używamy PK niezwiązanego z biznesem, jest zapewnienie, że nasz system ma łatwą i spójną metodę określania tego, czego chce użytkownik.

Widzę, że odpowiedziałeś komentarzem: MessageSender, MessageRecipient, TimeSent (dla wiadomości). W ten sposób możesz nadal mieć niejednoznaczność (na przykład z generowanymi przez system komunikatami wyzwalającymi coś, co często się zdarza). I jak zamierzasz tutaj zweryfikować MessageSender i MessageRecipient? Załóżmy, że zweryfikujesz je przy użyciu imienia, nazwiska, daty i daty urodzenia, w końcu trafisz na sytuację, w której urodzą się 2 osoby tego samego dnia o tym samym nazwisku. Nie wspominając już o tym, że spotka Cię wiadomość o nazwie tacostacostacos-America-1980-Doc Brown-France-1965-23/5/2014-11:43:54.003UTC+200. To potwór o imieniu i nadal nie masz gwarancji, że będziesz mieć tylko 1 z nich.

powodem, dla którego używamy klucza podstawowego jest to, że WIEMY, że będzie unikalny przez cały okres użytkowania oprogramowania, bez względu na wprowadzane dane, i WIEMY, że będzie to przewidywalny format (co się stanie, jeśli powyższy klucz ma myślnik w nazwie użytkownika? cały twój system się psuje).

Nie musisz pokazywać swojego ID swojemu użytkownikowi. Możesz to ukryć (w razie potrzeby za pomocą adresu URL).

Innym powodem, dla którego PK jest tak przydatny, jest coś, co można wywnioskować z powyższego: PK sprawia, że ​​nie trzeba zmuszać komputera do interpretacji kodu generowanego przez użytkownika. Jeśli chiński użytkownik użyje twojego kodu i wpisze kilka chińskich znaków, twój kod nagle nie musi być w stanie pracować z nimi wewnętrznie, ale może po prostu użyć Guida wygenerowanego przez system. Jeśli masz arabskiego użytkownika, który zaczyna pisać po arabsku, twój system nie musi sobie z tym poradzić wewnętrznie, ale może po prostu zignorować to, że tam jest.

Jak powiedzieli inni, przewodnik jest czymś, co można przechowywać wewnętrznie w ustalonym rozmiarze. Wiesz, z czym pracujesz i jest to coś, co może być powszechnie stosowane. Nie musisz tworzyć reguł projektowych dotyczących sposobu tworzenia określonego identyfikatora i zapisywania go. Jeśli twój system przyjmuje tylko pierwsze 10 liter imienia, nie widzi żadnej różnicy między Michaelem Guggenheimerem a Michaelem Gugsteinem, i myli je 2. Jeśli odetniesz go na dowolnej długości, możesz wpaść w zamieszanie. Jeśli ograniczysz wprowadzanie danych przez użytkownika, możesz napotkać problemy z ograniczeniami użytkownika.

Kiedy patrzę na istniejące systemy, takie jak Dynamics CRM, używają również klucza wewnętrznego (PK), aby użytkownik mógł wywołać pojedynczy rekord. Jeśli użytkownik ma zapytanie, które nie wiąże się z identyfikatorem, zwraca tablicę możliwych odpowiedzi i pozwala mu wybrać. Jeśli istnieje jakakolwiek szansa na dwuznaczność, dadzą wybór użytkownikowi.

Wreszcie, jest to także kwestia bezpieczeństwa poprzez niejasność. Jeśli nie znasz identyfikatora rekordu, jedyną opcją jest odgadnięcie. jeśli identyfikator jest łatwy do odgadnięcia (ponieważ informacje, z których jest wykonany, są publicznie dostępne), każdy może go zmienić. Możesz nawet nakłonić użytkownika do zmiany go za pomocą klasycznych metod CSRF lub XSS. Teraz, oczywiście, twoje zabezpieczenia powinny już były uwzględnione i zminimalizowane przed opublikowaniem wersji na żywo, ale powinieneś utrudnić potencjalne nadużycia.

Nzall
źródło
1

Wydając identyfikator dla systemu zewnętrznego, należy podawać tylko identyfikatory URI lub klucz lub zestaw kluczy, które mają te same właściwości co identyfikator URI, zamiast ujawniać bezpośrednio klucz podstawowy bazy danych (od tego momentu będę się odnosił do zarówno URI, jak i klucz lub zestaw kluczy, które mają takie same właściwości jak URI jak tylko URI, innymi słowy poniższy URI niekoniecznie oznacza RFC 3986 URI).

Identyfikator URI może zawierać klucz podstawowy obiektu, ale nie musi składać się z kluczy alternatywnych. To naprawdę nie ma znaczenia. Ważne jest to, że tylko system, który generuje identyfikator URI, może rozdzielać lub łączyć identyfikator URI, aby zrozumieć, czym jest wskazany obiekt. Systemy zewnętrzne powinny zawsze używać identyfikatora URI jako nieprzezroczystego identyfikatora. Nie ma znaczenia, czy użytkownik może rozpoznać, że jedna część identyfikatora URI jest w rzeczywistości kluczem zastępczym bazy danych, czy składa się z kilku kluczy biznesowych zebranych razem, czy też jest to podstawa 64 tych wartości. Te są nieistotne. Liczy się to, że nie trzeba wymagać, aby system zewnętrzny rozumiał, co oznacza identyfikator, aby użyć identyfikatora. Systemy zewnętrzne nigdy nie powinny być zobowiązane do parsowania komponentów w obrębie identyfikatora lub łączenia identyfikatora z innymi identyfikatorami w celu odniesienia się do czegoś w twoim systemie.

Korzystanie z GUID spełnia niektóre z tych kryteriów, jednak identyfikacja taka jak GUID może być trudna do wyrejestrowania z powrotem do obiektu, nawet w systemie, więc klucze, które są nieprzejrzyste nawet dla twojego systemu, takie jak GUID, powinny być stosowane tylko wtedy, gdy klient analizuje URI / identyfikator stanowi zagrożenie dla bezpieczeństwa.

Wracając do przykładu VoIP, powiedz, że dostawca VoIP może być jednoznacznie określony przez (VoIPProviderID) lub (Nazwa, URL) lub (GUID). Gdy system zewnętrzny musi zaktualizować dostawcę VoIP, może po prostu przekazać PUT / provider / by-id / 1234 lub PUT /provider/foo-voip/bar-domain.comlub PUT /3F2504E0-4F89-41D3-9A0C-0305E82C3301twój system zrozumie, że system zewnętrzny chce zaktualizować VoIPProvider. Te identyfikatory URI są generowane przez twój system i tylko twój system musi zrozumieć, że wszystkie one oznaczają to samo. System zewnętrzny powinien traktować wszystko, co znajduje się w URI, w zasadzie jako PUT <whatever>.

Załóżmy, że masz dane różnych dostawców VoIP przechowywane w różnych tabelach z różnymi schematami (a zatem zupełnie inny zestaw kluczy identyfikuje każdego dostawcę VoIP na podstawie tabeli, w której są przechowywane). Gdy masz identyfikator URI, system zewnętrzny może uzyskać do niego jednolity dostęp, bez względu na to, jak Twój system identyfikuje konkretnego dostawcę VoIP. Dla systemu zewnętrznego jest to po prostu nieprzezroczysty wskaźnik.

Kiedy system używa identyfikatora URI do odwoływania się do obiektów w taki sposób, nie tracisz nic na temat sposobu implementacji systemu. Generujesz identyfikator URI, a klient po prostu przekazuje go z powrotem.

Lie Ryan
źródło
0

Będę musiał celować w to szalenie niedokładne i naiwne stwierdzenie:

Być może przyjazny dla użytkownika identyfikator jest w tym przypadku bezużyteczny; w końcu dostawcy VoIP są firmami, których nazwy są zwykle wyraźne w sensie komputerowym, a nawet wystarczająco wyraźne w sensie ludzkim ze względów biznesowych.

Nazwy są okropne jak klucze, ponieważ często się zmieniają. Firma może mieć wiele nazw w ciągu swojego życia, firma może łączyć, dzielić, ponownie łączyć, tworzyć odrębną spółkę zależną do określonych celów podatkowych, która ma 0 pracowników, ale wszystkich klientów, którzy następnie zatrudniają pracowników z zupełnie innej spółki zależnej.

Następnie wchodzimy w fakt, że nazwy firm nie są nawet zdalnie unikalne, jak pokazuje przełomowy Apple vs. Apple .

Dobry obiektowy obiekt odwzorowujący lub frameworki powinien wyodrębnić klucze podstawowe i uczynić je niewidocznymi, ale one tam są i zazwyczaj będą jedynym sposobem na jednoznaczną identyfikację obiektu w bazie danych.

Dla porównania wolę, jak django sobie z tym radzi:

class VoipProvider(models.Model):
    name=fields.TextField()
    address=fields.TextField()

class Customer(models.Model):
    name=fields.TextField()
    address=fields.TextField()
    voipProvider=fields.ForeignKeyField(VoipProvider)

W ten sposób dane dostawcy klienta mogą być dostępne w kodzie za pomocą:

myCustomer.voipProvider.name #returns the name of the customers VOIP Provider.

Chociaż klucze podstawowe / obce są niewidoczne, są tam i mogą być używane do uzyskiwania dostępu do przedmiotów, ale są abstrakcyjne.


źródło
Masz całkowitą rację, ale myślę, że miałem na myśli, że „w niektórych domenach może istnieje naturalna krotka wartości, które zawsze są unikalne” Jeśli się zmienią, ale nadal są wyjątkowe, nadal identyfikują jeden rekord.
tacos_tacos_tacos
0

Myślę, że często wciąż niepoprawnie patrzymy na ten problem z perspektywy DB: och, nie ma naturalnego klucza, więc musimy stworzyć klucz zastępczy. O nie, nie możemy odsłonić klucza zastępczego z powrotem do obiektów domeny, to jest nieszczelne itp.

Czasem jednak lepszym rozwiązaniem jest: jeśli obiekt biznesowy (domena) nie ma klucza naturalnego, być może należy go podać. Jest to podwójny problem z domeną biznesową: po pierwsze, rzeczy wymagają tożsamości, nawet przy braku baz danych. Po drugie, chociaż staramy się udawać, że wytrwałość jest jakimś abstrakcyjnym pomysłem niewidocznym dla domeny, rzeczywistość jest taka, że ​​wytrwałość jest nadal koncepcją biznesową. Oczywiście istnieją problemy, w których wybrany klucz naturalny nie jest obsługiwany przez DB jako klucz podstawowy (np. GUID w niektórych systemach) - w takim przypadku trzeba będzie dodać klucz zastępczy.

W ten sposób kończysz w bardzo podobnym miejscu, np. Twój klient ma identyfikator liczby całkowitej, ale zamiast czuć się źle, ponieważ wyciekł z DB do domeny, czujesz się szczęśliwy, ponieważ firma zgodziła się, aby wszystkim klientom przypisano identyfikator ID i utrwalasz to w DB, jak musisz. Nadal możesz wprowadzić surogat, np. W celu wsparcia zmiany nazwy identyfikatora klienta.

Podejście to oznacza również, że jeśli obiekt domeny uderza w warstwę trwałości i nie ma identyfikatora, to prawdopodobnie jest to jakiś obiekt wartości, więc nie potrzebuje identyfikatora.

Kredowy
źródło