Wird in einer Viele-zu-Viele-Tabelle (Junction-Tabelle) eine eindeutige ID-Spalte benötigt?

22

Einige Projekte wurden mit EF gestartet, aber ich hatte einige Fragen zu Verknüpfungstabellen und Schlüsseln usw. Nehmen wir an, ich habe eine Tabelle mit Anwendungen und Berechtigungen. Anwendungen haben viele Berechtigungen und jede Berechtigung kann zu vielen Anwendungen gehören (viele-zu-viele).

Jetzt sind die Anwendungs- und Berechtigungstabellen einfach:

Applications
--------------
PK  ApplicationID
    Name

Permissions
--------------
PK  PermissionID
    Name

Aber wie geht das am besten am Join-Tisch? Ich habe diese zwei Möglichkeiten:

ApplicationPermissions
-----------------------
PK  ApplicationPermissionID
CU  ApplicationID
CU  PermissionID

ODER

ApplicationPermissions
-----------------------
CPK ApplicationID
CPK PermissionID

PK = Primary Key
CPK = Composite Primary Key
CU = Composite Unique Index

Wurdest du jemals verbrannt, als du es auf die eine oder andere Weise getan hast? ist es streng bevorzugt? Mir ist der Gedanke gekommen, dass viele der "Unterschiede" durch mein Repository-Muster abstrahiert werden (zum Beispiel würde ich fast nie ein gesamtes Berechtigungsobjekt erstellen und es einer Anwendung hinzufügen, sondern es anhand der ID oder des eindeutigen Namens oder irgendwas), aber ich schätze, ich suche nach Horrorgeschichten, so oder so.

solidau
quelle

Antworten:

20

Ich glaube, Sie meinen "Junction" -Tabelle, nicht "Join" -Tabelle.

Es ist nicht erforderlich, dass eine Junction-Tabelle ein eigenes ID-Feld hat. Sie müssten niemals einer solchen ID beitreten oder nach ihr filtern. Sie würden nur die IDs der Tabellen, die Sie zuordnen, verknüpfen oder filtern. Eine ID in einer Junction-Tabelle ist eine Verschwendung von Speicherplatz.

Die "beste" Option ist es also, die ID zu vermeiden. In der Regel hat eine Junction-Tabelle 2 überdeckende Indizes. Jeder Deckungsindex verwendet eine der zugeordneten IDs als primäres Sortierfeld.

Aber "das Beste" ist noch lange nicht. Es ist ein sehr kleines Problem, ein redundantes ID-Feld zu haben. Sie werden keine Horrorgeschichten über eine kleine Menge verschwendeter Festplatten haben. Die ID "stiehlt" den Clustered-Index nicht, da Sie ohnehin keine Cluster für die zugeordnete Kombination erstellen möchten.

Wenn Ihr Framework möchte, dass alle Tabellen eine ID haben, wählen Sie diese. Wenn die Datenbankstandards Ihres Teams vorschreiben, dass alle Tabellen eine ID haben müssen, wählen Sie diese aus. Wenn nicht, dann meide es.

mike30
quelle
2
Nun, Sie haben bereits festgestellt, dass das Hinzufügen einer ID eine geringfügige Konzession ist, die durch die potenziellen Vorteile leicht zu überwinden ist. Daher scheint es mir (angesichts der Tatsache, dass eine eindeutige ID in jeder Tabelle in den meisten DBMS und ORM mehr oder weniger die beste Vorgehensweise darstellt). Sie würden es vorziehen , eine ID als "beste" oder "Standard" -Option zu haben, anstatt keine zu haben.
Robert Harvey
4
"Sie müssten sich niemals einer solchen ID anschließen oder sie abfragen" - "Niemals" in einer Technologiesituation zu sagen, fordert genau dies dazu auf. Das heißt, es gibt Zeiten, in denen Sie dieser Verknüpfungstabelle beitreten (ja, ich habe gehört, dass sie mehr als eine Verknüpfungstabelle als eine Kreuzungstabelle bezeichnet wird), und zwar zu einer vierten Tabelle, da die verknüpften Entitäten tatsächlich a sind Geschäftsobjekt ihrer eigenen.
Jesse C. Slicer
4
@RobertHarvey. Eine ID ist eine bewährte Methode für Entitäten. Eine Junction ist jedoch eher ein Implementierungsdetail für viele-viele-Beziehungen und keine eigenständige Entität. Wie Jesse C. jedoch ausführt, gibt es Fälle, in denen eine Kreuzung als Geschäftseinheit angesehen werden könnte.
mike30
1
"Verschwendung von Speicherplatz." - Ich denke, einige Engines (InnoDB?) Erstellen sowieso einen (internen) Primärschlüssel, wenn Sie keinen selbst erstellen. Sie gewinnen also möglicherweise nicht wirklich Speicherplatz, wenn Sie keinen haben.
Alex
@Alex. Sie setzen eine zusammengesetzte PK auf die zugeordneten IDs.
mike30
11

Im Laufe der Jahre habe ich mir angewöhnt, jeder Tabelle "TableName" ausnahmslos einen automatisch generierten Primärschlüssel "TableNameID" zuzuweisen, auch nicht für Junction-Tabellen. Ich kann sagen, ich habe es nie bereut, weil es beim Erstellen von generischem Code, der etwas für "alle Tabellen" oder "einige Tabellen" oder für "viele Zeilen mehrerer verschiedener Tabellen" tut, vieles einfacher macht.

Wenn Sie beispielsweise aufgefordert werden, einige Zeilen verschiedener Tabellen (oder Verweise auf diese) in einer Datei oder im Speicher zu speichern, beispielsweise zu Protokollierungszwecken, ist es sehr praktisch, wenn Sie im Voraus wissen, dass Sie nur genau eine speichern müssen Tabellenname & genau eine Integer-ID, und Sie müssen sich nicht mit "Sonderfällen" auseinandersetzen.

Wenn Sie mit kombinierten PKs beginnen, werden Sie wahrscheinlich einige Male später auf die Notwendigkeit von kombinierten Fremdschlüsseln stoßen (da Sie möglicherweise an einem Punkt angelangt sind, an dem Sie Ihrer ApplicationPermissionsTabelle eine FK-Referenz hinzufügen möchten ). Dann kann die nächste Anforderung sein, dass diese FK in Verbindung mit anderen Attributen oder Fremdschlüsseln eindeutig ist - was insgesamt zu einer erhöhten Komplexität führt. Natürlich nichts, was für die meisten modernen DB-Systeme nicht zu handhaben ist, aber eine einheitliche Lösung erleichtert Programmierern oft das Leben.

Und schließlich SELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...)funktioniert eine Anweisung wie mit einer einzelnen Spalte als Primärschlüssel gut, aber ich habe noch nie einen SQL-Dialekt gesehen, mit dem Sie dies mit kombinierten Schlüsseln tun können. Wenn Sie vorher wissen, dass Sie eine solche Abfrage nie benötigen, ist dies in Ordnung. Seien Sie jedoch nicht überrascht, wenn Sie morgen eine Anforderung erhalten, die mit dieser Art von SQL am einfachsten zu lösen ist.

Wenn Sie erwarten, dass Ihre ApplicationPermissionsTabelle mehrere hundert Millionen Zeilen enthält, sollten Sie natürlich in Betracht ziehen, so etwas wie a zu vermeiden ApplicationPermissionsID.

Doc Brown
quelle
Obwohl ich am Ende nicht deine Antwort gewählt habe. Ich mag Aspekte davon. Vielen Dank für Ihre Gedanken (upvote).
Solidau
6

Obwohl Mikes Antwort gut ist, habe ich hier die Gründe, warum ich ein separates ID-Feld hinzufügen würde oder nicht.

  1. Verwenden Sie ein separates ID-Feld für die Junction- / Join-Tabelle, wenn es andere Felder als die ID enthält . Dies führt dazu, dass es sich um eine erstklassige Entität handelt.

  2. Ziehen Sie die Verwendung eines separaten ID-Felds in Betracht, wenn APIs oder eine vorhandene Logik dazu neigen, einzelne Felder zum Abrufen / Bearbeiten von Entitäten zu verwenden. Dies kann anderen helfen, Ihren Code im Rahmen eines größeren Projekts zu verfolgen.

  3. Verwenden Sie es nicht, wenn es keinen spezifischen Nutzen gibt (KISS). EF weiß, wie man mit dieser Art von Tabelle umgeht, und eine zusammengesetzte eindeutige Einschränkung kann manchmal übersehen werden, wenn andere Leute versuchen, diese Art von Beziehung zu verstehen. Außerdem versuche ich beim Normalisieren, den kleinstmöglichen Schlüssel zu verwenden, der das Tupel eindeutig definiert . In Ihrem zweiten Beispiel verfügen Sie effektiv über zwei separate Kandidatenprimärschlüssel.

Zachary Yates
quelle
-5
table Person
   Id int identity(1,1) not null primary key
   ...other fields go here...
table Address
   Id int identity(1,1) not null primary key
   ...other fields go here...
table PersonAddress
   Id int identity(1,1) not null primary key
   PersonId int not null
   AddressId int not null

Denken Sie daran, einen Index und einen Fremdschlüssel für beide PersonIdund zu erstellen AddressId.

Egal, was andere für "besser" oder "Sie sollten" halten, dies ist die einfachste und einfachste Möglichkeit, die Datenbank ordnungsgemäß funktionieren zu lassen.

16PlusYearsAsADeveloper
quelle
1
Ich denke, ein Problem bei diesem Ansatz ist, dass das Schema zwei PersonAddressZeilen mit identischen PersonIdund AddressIdWerten zulässt .
Sam