È necessaria una colonna ID univoca in una tabella molti-a-molti (giunzione)?

20

Avvio di alcuni progetti con EF, ma avevo alcune domande su unire tabelle e chiavi, ecc. Diciamo che ho una tabella di applicazioni e una tabella di permessi. Le applicazioni hanno molte autorizzazioni e ogni autorizzazione può appartenere a molte applicazioni (molte a molte).

Ora, le tabelle di autorizzazione e autorizzazione sono semplici:

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

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

Ma qual è il modo migliore per fare il tavolo dei join? Ho queste due opzioni:

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

o

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

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

Sei mai stato bruciato a farlo in un modo rispetto all'altro? è strettamente preferenziale? Mi è venuto in mente che molte delle "differenze" verranno sottratte dal mio modello di repository (ad esempio, non creerei quasi mai un intero oggetto di autorizzazione e lo aggiungo a un'applicazione, ma lo faccio per ID o nome univoco o qualcosa), ma suppongo che sto cercando storie dell'orrore, in un modo o nell'altro.

    
posta solidau 09.01.2013 - 21:32
fonte

4 risposte

19

Credo che tu intenda la tabella "junction", non la tabella "join".

Non è necessario che una tabella di giunzione abbia il proprio campo ID. Non avresti mai bisogno di unirti o filtrare su un tale ID. Dovresti unire o filtrare solo gli ID delle tabelle che stai mappando. Un ID su una tabella di congiunzione è uno spreco di spazio su disco.

Quindi l'opzione "migliore" è evitare l'ID. In genere una tabella di giunzione avrà 2 indici di copertura. Ciascun indice di copertura che utilizza uno degli ID associati come campo di ordinamento principale.

Ma il "meglio" non è da molto tempo. È un problema molto secondario avere un campo ID ridondante. Non avrai storie horror su una piccola quantità di disco sprecato. L'ID non "ruba" l'indice cluster perché non vuoi comunque cluster sulla combo mappata.

Se il tuo framework vuole che tutte le tabelle abbiano un ID, allora cerca di farlo. Se gli standard del database del tuo team dettano che tutte le tabelle devono avere un ID, allora vai a prenderlo. In caso contrario, evitalo.

    
risposta data 09.01.2013 - 22:02
fonte
9

Nel corso degli anni ho preso l'abitudine di dare a ogni tabella "TableName" una chiave primaria generata automaticamente "TableNameID", senza eccezioni, nemmeno per le tabelle di junction. Posso dire che non me ne sono mai pentito, perché rende molte cose più semplici quando si crea codice generico che fa qualcosa per "tutte le tabelle" o "alcune tabelle" o per "molte righe di più tabelle diverse".

Ad esempio, se qualcuno ti chiede di memorizzare alcune righe di tabelle diverse (o riferimenti a quelle) in un file o in memoria, ad esempio, per scopi di registrazione, è molto utile quando sai in anticipo che devi solo memorizzare esattamente un nome di tabella & esattamente un ID intero e non devi occuparti di "casi speciali".

Un'altra cosa, quando inizi con PK combinati, probabilmente dovrai ricorrere alcune volte in seguito alla necessità di combinazioni di chiavi esterne (dato che potresti arrivare ad un punto in cui vuoi aggiungere un riferimento FK alla tua tabella ApplicationPermissions ) . Quindi il prossimo requisito potrebbe essere quello di rendere questo FK univoco in combinazione con altri attributi o chiavi esterne - il che comporterà una maggiore complessità complessiva. Nulla che non sia possibile gestire per la maggior parte dei sistemi DB moderni, ma una soluzione uniforme rende la vita dei programmatori spesso molto più semplice.

E infine, un'istruzione come SELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...) funziona bene con una singola colonna come chiave primaria, ma non ho mai visto finora un dialetto SQL che ti permetta di farlo con le chiavi combinate. Se sai in anticipo che non avrai mai bisogno di una query come questa, bene, ma non stupirti se domani riceverai un requisito che sarà risolto più facilmente con questo tipo di SQL.

Naturalmente, quando ti aspetti che la tua tabella ApplicationPermissions contenga centinaia di milioni di righe, dovresti prendere in considerazione di evitare qualcosa come ApplicationPermissionsID .

    
risposta data 10.01.2013 - 17:52
fonte
6

Mentre la risposta di Mike è buona, ecco i motivi per cui aggiungerei un campo ID separato o no.

  1. Considera di utilizzare un campo ID separato per la tabella junction / join se contiene campi diversi dall'ID . Questo tende a notare che è un'entità di prima classe.

  2. Considera l'utilizzo di un campo ID separato se le API o qualsiasi logica esistente tendono a utilizzare singoli campi per recuperare / modificare entità. Ciò può aiutare altre persone a seguire il tuo codice nel contesto di un progetto più ampio.

  3. Non usarlo se non ci sono vantaggi specifici (KISS). EF sa come gestire questo tipo di tabella e talvolta può mancare un vincolo univoco composito quando altre persone cercano di capire questo tipo di relazione. Inoltre, durante la normalizzazione cerco di utilizzare la più piccola chiave possibile che definisca in modo univoco la tupla . Nel tuo secondo esempio, hai effettivamente 2 chiavi primarie candidate separate.

risposta data 10.01.2013 - 19:12
fonte
-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

Ricorda di creare un indice e una chiave esterna sia in PersonId che in AddressId .

Indipendentemente da ciò che gli altri pensano siano "migliori" o "dovresti", questo è il modo più semplice e semplice per consentire al database di funzionare correttamente.

    
risposta data 10.01.2013 - 18:57
fonte

Leggi altre domande sui tag