Adressierung der Tatsache, dass Primärschlüssel nicht Teil Ihrer Geschäftsdomäne sind

25

In fast allen Fällen gehören Primärschlüssel nicht zu Ihrer Geschäftsdomäne. Sicher, Sie haben möglicherweise einige wichtige benutzerbezogene Objekte mit eindeutigen Indizes ( UserNamefür Benutzer oder OrderNumberfür Aufträge), aber in den meisten Fällen besteht keine geschäftliche Notwendigkeit , Domänenobjekte offen anhand eines einzelnen Wertes oder Wertesatzes zu identifizieren administrativer Benutzer. Selbst in diesen Ausnahmefällen, insbesondere wenn Sie GUIDs ( Global Unique Identifiers) verwenden , möchten Sie einen alternativen Schlüssel verwenden, anstatt den Primärschlüssel selbst bereitzustellen.

Wenn mein Verständnis von domänengetriebenem Design korrekt ist, müssen und sollten Primärschlüssel nicht offengelegt werden, und es sollte ein guter Befreiungsschlag erfolgen. Sie sind hässlich und verkrampfen meinen Stil. Wenn wir uns jedoch dafür entscheiden, keine Primärschlüssel in das Domänenmodell aufzunehmen, ergeben sich folgende Konsequenzen:

  1. Datenübertragungsobjekte ( Data Transfer Objects, DTO) , die ausschließlich aus Kombinationen von Domänenmodellen abgeleitet werden, verfügen nicht über Primärschlüssel
  2. Eingehende DTOs haben keinen Primärschlüssel

Ist es also sicher zu sagen, dass Sie, wenn Sie wirklich rein bleiben und Primärschlüssel in Ihrem Domain-Modell eliminieren möchten, bereit sein sollten, jede Anfrage in Bezug auf eindeutige Indizes für diesen Primärschlüssel zu bearbeiten?

Anders ausgedrückt: Welche der folgenden Lösungen ist der richtige Ansatz, um bestimmte Objekte nach dem Entfernen der PK in Domänenmodellen zu identifizieren?

  1. In der Lage zu sein, die Objekte, mit denen Sie sich befassen müssen, anhand anderer Attribute zu identifizieren
  2. Wiederherstellen des Primärschlüssels im DTO; dh die PK bei der Zuordnung von der Persistenz zur Domäne entfernen und dann die PK bei der Zuordnung von der Domäne zur DTO neu kombinieren?

EDIT: Lassen Sie uns dies konkretisieren.

Sagen Sie mein Domain - Modell ist , VoIPProviderwelches enthält Felder wie Name, Description, URL, sowie Referenzen wie ProviderType, PhysicalAddressund Transactions.

Angenommen, ich möchte einen Webdienst erstellen, mit dem privilegierte Benutzer VoIPProviders verwalten können .

Vielleicht ist eine benutzerfreundliche ID in diesem Fall nutzlos. VoIP-Anbieter sind schließlich Unternehmen, deren Namen aus geschäftlichen Gründen in der Regel im Computersinn und sogar im menschlichen Sinn eindeutig genug sind. Es mag also genügen zu sagen, dass ein Unikat VoIPProvidervollständig von bestimmt wird (Name, URL). Angenommen, ich benötige eine Methode PUT api/providers/voip, mit der privilegierte Benutzer VoIPAnbieter aktualisieren können. Sie senden ein VoIPProviderDTO, das viele, aber nicht alle Felder enthält VoIPProvider, einschließlich einiger potenzieller Abflachungen. Ich kann ihre Gedanken jedoch nicht lesen und sie müssen mir immer noch mitteilen, über welchen Anbieter wir sprechen.

Anscheinend habe ich 2 (vielleicht 3) Optionen:

  1. Fügen Sie einen Primär- oder Alternativschlüssel in mein Domain-Modell ein und senden Sie ihn an das DTO und umgekehrt
  2. Identifizieren Sie den Anbieter, den wir interessieren, über den eindeutigen Index wie (Name, Url)
  3. Führen Sie eine Art Zwischenobjekt ein, das immer auf eine Weise zwischen Persistenzschicht, Domäne und DTO abgebildet werden kann, die keine Implementierungsdetails über die Persistenzschicht preisgibt - beispielsweise durch Einfügen einer speicherinternen temporären ID, wenn von Domäne zu DTO und zurück gewechselt wird.
tacos_tacos_tacos
quelle
1
Hinweis zum Nachdenken: Oft wird die Kommunikation mit Domain-Experten verarmt, wenn Ersatz-PK verwendet wird, wenn ein guter Geschäftsschlüssel vorhanden ist. Es scheint, dass wir am Ende für das ORM-Framework arbeiten, anstatt umgekehrt.
Tulains Córdova
@ user61852 gut, unabhängig von ORM, auch wenn Sie wirklich niedrig sind, benötigen Sie immer noch einen Primärschlüssel für die Implementierung der Datenbankschicht. Ich bin damit einverstanden, dass die Ersatz-PK Ihnen Vorteile gegenüber der tatsächlichen PK bietet, die von einem bestimmten Persistenzmechanismus verwendet wird. Wenn diese PK jedoch wirklich ein aussagekräftiges Geschäftsobjekt darstellt, ist sie zwangsläufig eindeutig und verfügt daher über mindestens eine eindeutige Definition einer geschäftsbezogenen Eigenschaft es nicht?
Tacos_Tacos_Tacos
1
Alle Vorteile von Surrogaten hängen mit dem Computer und nicht mit dem Menschen zusammen.
Tulains Córdova
2
@ user61852: Ich stimme zu 100% zu (habe ich etwas anderes geschrieben?). Verwenden Sie für die Kommunikation einen "Geschäftsschlüssel". Fügen Sie eindeutige Einschränkungen für jeden Geschäftsschlüssel hinzu. Vermeiden Sie jedoch die Verwendung von Geschäftsschlüsseln, um Ihre Datenbankreferenzen tatsächlich zu implementieren.
Doc Brown
2
Business Keys sind auf ewig einzigartig - bis sie es nicht sind. Wenn Sie in diesem Fall die Geschäftsschlüssel als Primärschlüssel verwenden, werden durch die Änderung der Geschäftsregeln weitere Aufgaben gelöst.
PSR

Antworten:

31

So lösen wir das (seit mehr als 15 Jahren, als nicht einmal der Begriff "domain driven design" erfunden wurde):

  • Wenn Sie das Domänenmodell einer Datenbankimplementierung oder einem Klassenmodell in einer bestimmten Programmiersprache zuordnen, haben Sie eine einfache, konsistente Regel wie "Für jedes einer relationalen Tabelle zugeordnete Domänenobjekt lautet der Primärschlüssel" TablenameID ".
  • Dieser Primärschlüssel ist vollständig künstlich, hat immer den gleichen Typ und keine geschäftliche Bedeutung - nur einen Ersatzschlüssel
  • Die "grafische Version" Ihres Domain-Modells (diejenige, mit der Sie mit Ihren Domain-Experten sprechen) enthält keine Primärschlüssel. Sie stellen sie nicht direkt den Experten zur Verfügung (aber Sie stellen sie allen zur Verfügung, die tatsächlich Code für das System implementieren).

Wenn Sie also einen Primärschlüssel für technische Zwecke benötigen (z. B. zum Zuordnen von Beziehungen zu einer Datenbank), steht Ihnen dieser zur Verfügung. Wenn Sie ihn jedoch nicht "sehen" möchten, ändern Sie Ihre Abstraktionsebene in das Modell "Domänenexperten" ". Und Sie müssen nicht "zwei Modelle" pflegen (eines mit und eines ohne PKs). Pflegen Sie stattdessen nur ein Modell ohne PKs und erstellen Sie mithilfe eines Codegenerators die DDL für Ihre DB, die die PK automatisch gemäß den Zuordnungsregeln hinzufügt.

Beachten Sie, dass dies nicht verbietet, neben dem Ersatz "Geschäftsschlüssel" wie eine zusätzliche "Bestellnummer" hinzuzufügen OrderID. Technisch gesehen werden diese Geschäftsschlüssel bei der Zuordnung zu Ihrer Datenbank zu alternativen Schlüsseln. Vermeiden Sie es einfach, diese zum Erstellen von Verweisen auf andere Tabellen zu verwenden. Verwenden Sie nach Möglichkeit immer lieber die Ersatzschlüssel, da dies die Dinge erheblich vereinfacht.

Zu Ihrem Kommentar: Die Verwendung eines Ersatzschlüssels zur Identifizierung von Datensätzen ist kein geschäftlicher Vorgang, sondern ein rein technischer Vorgang. Um dies zu verdeutlichen, sehen Sie sich Ihr Beispiel an: Solange Sie keine zusätzlichen Unique-Contraints definieren, können zwei VoIPProvider-Objekte mit derselben Kombination aus (Name, URL), aber unterschiedlichen VoIPProviderIDs vorhanden sein.

Doc Brown
quelle
Was ist mit dem Schritt, das Domänenobjekt aus dem zurückgegebenen Persistenzobjekt (Entität oder Tabellenzeilenmodell oder was auch immer) zu übernehmen, zu DTO zu wechseln und es wieder aufzunehmen und zur Persistenz zurückzukehren? Erfolgt dies nur über einen Ersatzschlüssel (dh eine geschäftsorientierte Definition der Eindeutigkeit), die eine Lösung für jede Persistenzoperation erfordert?
Tacos_Tacos_Tacos
1
@tacos_tacos_tacos: Halten wir uns an Ihr VoIPProvider-Beispiel. Ich würde Ihrem DTO tatsächlich eine "VoIPProviderID" hinzufügen, zumindest auf der "Implementierungsseite" (wenn Sie auch eine grafische Version für Ihre Domain-Experten haben, würde ich sie dort wahrscheinlich nicht anzeigen). Für Aktualisierungszwecke sollte die Standardmethode zum Identifizieren eines bestimmten VoIPProviders die "VoIPProviderID" sein, die Sie beim Abrufen der Daten aus der Datenbank abgerufen haben. Wenn Benutzer Ihrer API eine Identifizierung durch (Name, URL) bevorzugen, geben Sie dies zusätzlich an. ...
Doc Brown
... und wenn die Leistung zu einem echten, messbaren Problem zu werden scheint, können Sie die Zuordnung (Name, URL) zu VoIPProviderID auch irgendwo zwischenspeichern. Ich würde aber nicht empfehlen, eine solche Optimierung vorzeitig durchzuführen.
Doc Brown
1
Natürliche Schlüssel scheinen manchmal wirklich zwingend, aber es ist zu leicht, sich zu verbrennen (z. B. "whoops, jetzt habe ich mehrere Mieter und das ist nicht mehr eindeutig").
Casey
1
@corsiKa: Im Zusammenhang mit der Frage des OP würde ich dringend empfehlen, einen rein automatisch generierten Schlüssel "OrderID" (der nicht auf einer Quittung gedruckt wird, sondern nur für interne Dinge wie Datenbankreferenzen verwendet wird) und einen separaten Geschäftsschlüssel zu haben "OrderNumber" (die zum Beispiel so etwas wie das aktuelle Jahr enthalten kann, die zum Sortieren und Filtern verwendet werden kann, die anschließend geändert / korrigiert werden kann und die auf Quittungen gedruckt werden kann). OP hat nach "Domain Driven Design" gefragt, die "OrderNumber" ist Teil des Domain-Modells, während die "OrderID" nur ein Implementierungsdetail ist.
Doc Brown
4

Sie müssen in der Lage sein, viele Objekte anhand eines eindeutigen Index zu identifizieren, und es ist nicht so, dass ein Primärschlüssel vorhanden ist (oder zumindest impliziert, dass einer vorhanden ist).

Es stehen eindeutige Indizes zur Verfügung, mit denen Sie Ihr DB-Schema weiter einschränken können, nicht als Wholesale-Ersatz für PKs. Wenn Sie keine PKs bereitstellen, weil sie hässlich sind, sondern stattdessen einen eindeutigen Schlüssel bereitstellen ... tun Sie eigentlich nichts anderes. (Ich nehme an, dass Sie hier keine PK- und Identitätsspalte verwechseln?)

gbjbaanb
quelle
Wenn ich eine Operation ausführen möchte, die eine bestimmte Instanz eines Domänenobjekts betrifft, das beibehalten wird, muss ich entweder explizit (über einen Schlüssel, entweder eine primäre oder eine alternative benutzerfreundliche ID, die eindeutig ist) in das DTO einbeziehen können zu dieser Tabelle und könnte ebenso gut ein Index für die Tabelle sein) oder implizit (über eine Kombination von Feldern, deren Werte einen bestimmten Datensatz eindeutig identifizieren) ... und außerdem müsste ich im praktischen Sinne das DTO senden eine Form der Änderungsnachverfolgung, wenn ich es anders machen würde (OriginalVal vs NewVal für alle Felder, die einen Datensatz identifizieren), nein?
Tacos_Tacos_Tacos
Ist die explizite v implizite Frage nicht der gleiche Unterschied? Sie können eine PK haben, die sich über mehrere Spalten erstreckt, genau wie ein eindeutiger Index. Ich sehe keinen Unterschied zwischen ihnen für Ihre Zwecke.
Gbjbaanb
Klar, wir könnten zum Beispiel eine PK auf mehreren Spalten haben. Aber für mich geht etwas über die Datenbank (den Speicher) verloren, was NICHTS mit dem Herzen und der Seele, der Geschäftseinheit, zu tun haben sollte. Wenn sich einige Tupel von Geschäftsentitätsfeldern auf die PK für die DB erstrecken, ist das großartig. Aber es sollte nicht unbedingt umgekehrt sein, oder?
Tacos_Tacos_Tacos
Sie überdenken es. Ein eindeutiger Index ist genauso ein Artefakt des DB-Schemas wie ein PK. Stellen Sie sich das so vor - eine PK ist nur der erste (oder primäre) eindeutige Index. Es ist "speziell", weil Sie in der Regel nur einen solchen Index benötigen.
Gbjbaanb
Richtig, aber jedes aussagekräftige Domain-Objekt sollte aus mindestens einem seiner geschäftsrelevanten Felder eindeutig identifizierbar sein, nicht wahr? Die Tatsache, dass dies einen Index in der Datenbank definiert, dient eher der Leistung als der einfachen Abfrage der Datenbank. Ich würde einen einspaltigen PK einem sechsspaltigen eindeutigen Index vorziehen, und sie dienen in Wirklichkeit unterschiedlichen Zwecken. Ein PK (oder ein Index mit einer kleinen Anzahl von Feldern) ist auch für die Bequemlichkeit des DBA / DBD verfügbar, oder?
Tacos_Tacos_Tacos
4

Ohne Primärschlüssel im Frontend gibt es keine einfache Möglichkeit für das Backend zu wissen, was Sie senden. Um dies zu beheben, müssten Sie eine Menge zusätzlicher Arbeit aufwenden, um die Daten zu analysieren. Dies würde die Leistung beeinträchtigen und wahrscheinlich mehr Zeit in Anspruch nehmen und hässlicher sein als das Anhängen eines Schlüssels an jedes Element.

Nehmen wir als Beispiel an, ich möchte eine Nachricht in einer App bearbeiten. Woher weiß die App, welche Nachricht ich ohne Primärschlüssel bearbeiten möchte? Das Bearbeiten von Objekten geschieht ständig und ohne Schlüssel ist dies nahezu unmöglich. Wenn Sie jedoch Objekte haben, die nicht bearbeitet werden sollen, überspringen Sie den Schlüssel, wenn Sie der Meinung sind, dass er ablenkt. Wenn Sie jedoch Primärschlüssel haben, kann dies die Leistung verbessern.

Johan
quelle
Nun, das ist die Nachricht ein extremes Beispiel, aber selbst dann würden wir wissen MessageSender, MessageRecipient, TimeSent- das sollte eindeutig sein.
Tacos_Tacos_Tacos
1
@tacos_tacos_tacos, wie erstellt man dann FKs für die anderen Tabellen? Es sollte MessageSenderId sein, die wahrscheinlich einer Users-Tabelle in UserId zugeordnet ist. Sie möchten den Benutzernamen nicht als Schlüssel zwischen den Tabellen verwenden, da sich dies ändern und zu einem Alptraum für die Wartung werden kann. Aus diesem Grund verbinden Sie Tabellen im Allgemeinen nur mit Primärschlüsseln und nicht mit einer anderen Spalte (es gibt sicherlich Ausnahmen). Diese Datenbankstruktur muss noch durchgesetzt werden. Jetzt können Sie jederzeit ein CQRS-Modell für Ihre App aufrufen. In diesem Fall ändern sich die Regeln. Vor allem, wenn Sie auch Event Sourcing einsetzen.
CaffGeek
4

Der Grund, warum wir eine nicht geschäftsbezogene PK verwenden, besteht darin, sicherzustellen, dass unser System über eine einfache und konsistente Methode verfügt, mit der ermittelt werden kann, was der Benutzer möchte.

Ich sehe, dass Sie mit einem Kommentar geantwortet haben: MessageSender, MessageRecipient, TimeSent (für eine Nachricht). Sie können auf diese Weise IMMER NOCH Mehrdeutigkeiten aufweisen (z. B. wenn vom System generierte Nachrichten aufgrund von Ereignissen ausgelöst werden, die häufig auftreten). Und wie werden Sie MessageSender und MessageRecipient hier validieren? Angenommen, Sie validieren sie mit FirstName, Lastname, DateOfBirth, und Sie werden irgendwann auf eine Situation stoßen, in der Sie zwei Personen haben, die am selben Tag mit genau demselben Namen geboren wurden. Ganz zu schweigen davon, dass Sie in eine Situation geraten, in der Sie eine Nachricht mit dem Namen haben tacostacostacos-America-1980-Doc Brown-France-1965-23/5/2014-11:43:54.003UTC+200. Das ist ein Monster mit einem Namen, und Sie können immer noch nicht garantieren, dass Sie nur einen davon haben.

Der Grund, warum wir einen Primärschlüssel verwenden, ist, dass wir wissen, dass er für die gesamte Lebensdauer der Software eindeutig ist, unabhängig davon, welche Daten eingegeben werden. Wir wissen, dass er ein vorhersehbares Format hat (was passiert, wenn Ihr oben genannter Schlüssel einen Bindestrich hat) In einem Benutzernamen geht dein ganzes System in die Scheiße.

Sie müssen Ihrem Benutzer Ihre ID nicht zeigen. Sie können dies verbergen (bei Bedarf über die URL im Klartext).

Ein weiterer Grund, warum ein PK so nützlich ist, lässt sich aus den obigen Ausführungen ableiten: Ein PK macht es so, dass Sie den Computer nicht zwingen müssen, vom Benutzer generierten Code zu interpretieren. Wenn ein chinesischer Benutzer Ihren Code verwendet und eine Reihe chinesischer Zeichen eingibt, muss Ihr Code plötzlich nicht mehr intern mit diesen arbeiten können, sondern kann einfach die vom System generierte Guid verwenden. Wenn Sie einen arabischen Benutzer haben, der arabische Schriften eingibt, muss Ihr System das nicht intern bewältigen, sondern kann im Grunde ignorieren, dass er dort ist.

Wie bereits erwähnt, kann eine Guid intern in einer festen Größe gespeichert werden. Sie wissen, womit Sie arbeiten, und es ist etwas, das universell einsetzbar ist. Sie müssen keine Entwurfsregeln dafür erstellen, wie Sie einen bestimmten Bezeichner erstellen und speichern. Wenn Ihr System nur die ersten 10 Buchstaben eines Namens akzeptiert, erkennt es keinen Unterschied zwischen Michael Guggenheimer und Michael Gugstein und verwirrt diese 2. Wenn Sie es in einer beliebigen Länge abschneiden, können Sie in Verwirrung geraten. Wenn Sie die Benutzereingabe begrenzen, können Probleme mit Benutzerbeschränkungen auftreten.

Wenn ich vorhandene Systeme wie Dynamics CRM betrachte, verwenden sie auch den internen Schlüssel (PK), mit dem der Benutzer einen einzelnen Datensatz abrufen kann. Wenn ein Benutzer eine Abfrage hat, zu der die ID nicht gehört, gibt er eine Reihe möglicher Antworten zurück und lässt den Benutzer eine Auswahl treffen. Wenn es eine Möglichkeit zur Mehrdeutigkeit gibt, geben sie dem Benutzer die Wahl.

Schließlich ist es auch ein gewisser Sicherheitsfaktor durch Unbekanntheit. Wenn Sie die Datensatz-ID nicht kennen, können Sie sie nur erraten. Wenn die ID leicht zu erraten ist (weil die Informationen, aus denen sie bestehen, öffentlich verfügbar sind), kann sie jeder ändern. Sie können den Benutzer sogar dazu anregen, ihn mithilfe klassischer CSRF- oder XSS-Methoden zu ändern. Natürlich sollte Ihre Sicherheit diese bereits berücksichtigt und gemindert haben, bevor Sie die Live-Version veröffentlichen. Sie sollten es jedoch immer noch schwieriger machen, potenziellen Missbrauch zu erleiden.

Nzall
quelle
1

Wenn Sie einen Bezeichner für ein externes System ausgeben, sollten Sie nur URIs oder alternativ einen Schlüssel oder eine Reihe von Schlüsseln angeben, die dieselben Eigenschaften wie ein URI haben, anstatt den Datenbankprimärschlüssel direkt bereitzustellen (von hier an verweise ich darauf beide URIs oder ein Schlüssel oder eine Reihe von Schlüsseln, die die gleichen Eigenschaften wie URIs wie nur URIs haben, mit anderen Worten, ein URI darunter bedeutet nicht notwendigerweise RFC 3986 URI).

Ein URI kann den Primärschlüssel des Objekts enthalten oder nicht, und er kann tatsächlich aus alternativen Schlüsseln bestehen oder nicht. Es ist nicht wirklich wichtig. Was zählt, ist, dass nur das System, das den URI generiert, den URI aufteilen oder kombinieren darf, um ein Verständnis dafür zu erhalten, was das referenzierte Objekt ist. Externe Systeme sollten den URI immer als undurchsichtige Kennung verwenden. Es spielt keine Rolle, ob ein menschlicher Benutzer erkennen kann, dass ein Teil des URI tatsächlich ein Datenbank-Ersatzschlüssel ist oder aus mehreren zusammengebündelten Geschäftsschlüsseln besteht oder dass es sich tatsächlich um eine Base64 dieser Werte handelt. Diese sind irrelevant. Was zählt, ist, dass das externe System nicht erforderlich sein sollte, um zu verstehen, was der Bezeichner bedeutet, um den Bezeichner zu verwenden. Externe Systeme sollten niemals aufgefordert werden, die Komponenten innerhalb des Bezeichners zu analysieren oder einen Bezeichner mit anderen Bezeichnern zu kombinieren, um auf etwas in Ihrem System zu verweisen.

Die Verwendung von GUID erfüllt einige dieser Kriterien. Allerdings kann es schwierig sein, Identifikatoren wie GUID in das Objekt zurückzuverweisen, auch wenn sie sich in Ihrem System befinden. Daher sollten Schlüssel, die für Ihr System undurchsichtig sind, wie GUIDs, nur verwendet werden, wenn der Client den URI / Identifikator tatsächlich analysiert ein Sicherheitsrisiko darstellt.

Gehen Sie zu Ihrem VoIP-Beispiel zurück und sagen Sie, dass ein VoIP-Anbieter entweder durch (VoIPProviderID) oder durch (Name, URL) oder durch (GUID) eindeutig bestimmt werden kann. Wenn ein externes System den VoIP-Provider aktualisieren muss, kann es einfach einen PUT / provider / by-id / 1234 übergeben oder PUT /provider/foo-voip/bar-domain.comoder PUT /3F2504E0-4F89-41D3-9A0C-0305E82C3301und Ihr System würde verstehen, dass das externe System den VoIPProvider aktualisieren möchte. Diese URIs werden von Ihrem System generiert und nur Ihr System muss verstehen, dass sie alle dasselbe bedeuten. Das externe System sollte einfach alles, was in der URI enthalten ist, als grundlegend behandeln PUT <whatever>.

Angenommen, Sie haben die Daten für verschiedene VoIP-Anbieter in verschiedenen Tabellen mit unterschiedlichen Schemata gespeichert (daher identifiziert ein völlig unterschiedlicher Schlüsselsatz jeden VoIP-Anbieter anhand der Tabelle, in der sie gespeichert sind). Wenn Sie eine URI haben, kann das externe System einheitlich auf sie zugreifen, ohne darauf zu achten, wie Ihr System den jeweiligen VoIP-Anbieter identifiziert. Zum externen System ist alles nur ein undurchsichtiger Zeiger.

Wenn Ihr System einen URI verwendet, um auf Objekte so zu verweisen, verlieren Sie nichts darüber, wie Sie Ihr System implementieren. Sie generieren den URI und der Client gibt ihn einfach an Sie zurück.

Lüge Ryan
quelle
0

Ich werde diese wild ungenaue und naive Aussage ins Visier nehmen müssen:

Vielleicht ist eine benutzerfreundliche ID in diesem Fall nutzlos. VoIP-Anbieter sind schließlich Unternehmen, deren Namen aus geschäftlichen Gründen in der Regel im Computersinn und sogar im menschlichen Sinn eindeutig genug sind.

Namen sind schrecklich wie Schlüssel, da sie sich häufig ändern. Eine Firma kann zu Lebzeiten viele Namen haben, die Firma kann fusionieren, splitten, wieder fusionieren, eine eigene Tochtergesellschaft für bestimmte Steuerzwecke gründen, die 0 Angestellte hat, aber alle Kunden, die dann Angestellte einer völlig anderen Tochtergesellschaft einstellen.

Dann stellen wir fest, dass Firmennamen nicht einmal im Entferntesten eindeutig sind, wie der Meilenstein Apple vs. Apple zeigt .

Ein guter relationaler Mapper oder Framework für Objekte sollte die Primärschlüssel abstrahieren und diese unsichtbar machen, aber sie sind vorhanden, und sie sind normalerweise die einzige Möglichkeit, ein Objekt in Ihrer Datenbank eindeutig zu identifizieren.

Als Referenz bevorzuge ich, wie Django damit umgeht :

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

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

Auf diese Weise können die Details eines Anbieters eines Kunden mit folgendem Code abgerufen werden:

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

Die Primär- / Fremdschlüssel sind zwar nicht sichtbar, befinden sich jedoch dort und können für den Zugriff auf Elemente verwendet werden, werden jedoch abstrahiert.


quelle
Sie haben vollkommen recht, aber ich denke, ich habe gemeint, dass "in einigen Bereichen möglicherweise ein natürliches Tupel von Werten existiert, die immer eindeutig sind". Wenn sie sich ändern, aber immer noch eindeutig sind, identifizieren sie immer noch einen einzelnen Datensatz.
Tacos_Tacos_Tacos
0

Ich denke, wir betrachten dieses Problem aus Sicht der DB oft noch immer falsch: Oh, es gibt keinen natürlichen Schlüssel, daher müssen wir einen Ersatzschlüssel erstellen. Oh nein, wir können den Ersatzschlüssel nicht wieder in den Domänenobjekten offen legen, das ist undicht usw.

Manchmal ist dies jedoch eine bessere Einstellung: Wenn ein Geschäftsobjekt (Domain) keinen natürlichen Schlüssel hat, sollte ihm möglicherweise einer gegeben werden. Hierbei handelt es sich um ein zweifaches Business-Domain-Problem: Erstens benötigen die Dinge eine Identität, auch wenn keine Datenbanken vorhanden sind. Zweitens, obwohl wir versuchen, so zu tun, als sei Persistenz eine abstrakte Idee, die für die Domäne unsichtbar ist, ist die Realität, dass Persistenz immer noch ein Geschäftskonzept ist. Offensichtlich gibt es Probleme, bei denen der ausgewählte natürliche Schlüssel von der Datenbank nicht als Primärschlüssel unterstützt wird (z. B. GUIDs auf einigen Systemen). In diesem Fall müssen Sie einen Ersatzschlüssel hinzufügen.

So landen Sie an einem sehr ähnlichen Ort, z. B. wenn Ihr Kunde eine ganzzahlige ID hat. Anstatt sich jedoch krank zu fühlen, weil diese von der DB an die Domain gelangt ist, sind Sie glücklich, weil das Unternehmen vereinbart hat, dass allen Kunden eine ID zugewiesen wird ID, und Sie bestehen darauf, dass die DB, wie Sie müssen. Es steht Ihnen weiterhin frei, einen Ersatz einzuführen, z. B. um die Umbenennung der Kunden-ID zu unterstützen.

Dieser Ansatz bedeutet auch, dass ein Domänenobjekt, das auf die Persistenzschicht trifft und keine ID hat, wahrscheinlich ein Wertobjekt ist und daher keine ID benötigt.

Chalky
quelle