Sono molto nuovo alla modellazione dei dati, e secondo Entity Framework di Microsoft, le tabelle senza chiavi primarie non sono consentite e apparentemente una cattiva idea. Sto cercando di capire perché questa è una cattiva idea e come sistemare il mio modello in modo da non avere questo buco.
Ho 4 tabelle nel mio modello attuale: Utente, Città, HelloCity e RateCity. È modellato come mostrato nell'immagine. L'idea è che molti utenti possono visitare molte città e un utente può valutare una città solo una volta, ma possono salutare una città molte volte. Per questo motivo, non avevo un PK nella tabella di HelloCity.
Qualche idea su come posso cambiarla per rispettare le migliori pratiche e perché questa è contraria alle migliori pratiche per cominciare?
Questa risposta è principalmente basata su opinioni / esperienze, quindi elencherò alcune ragioni che mi vengono in mente. Si noti che questo non è esaustivo.
Ecco alcuni motivi per cui dovresti usare le chiavi primarie (PK):
TableA.id
è referenziato da TableB.table_a_id
? Se TableB.table_a_id = 5
, allora sei sicuro di avere una riga con id = 5
in TableA
. L'integrità e la coerenza dei dati vengono mantenute e ciò è positivo. Secondo me, non avere un PK potrebbe essere legale (cioè l'RDBMS ti permetterà), ma non è morale (cioè non dovresti farlo). Penso che dovresti avere ragioni straordinariamente buone / potenti per discutere di non usare un PK nelle tue tabelle DB (e le troverei comunque discutibili), ma in base al tuo attuale livello di esperienza (cioè dici di essere "nuovo alla modellizzazione dei dati"), direi che non è ancora sufficiente tentare di giustificare la mancanza di PK.
Ci sono più ragioni, ma spero che questo ti dia abbastanza per risolverlo.
Per quanto riguarda le tue relazioni M:M
, devi creare una nuova tabella, chiamata tabella associativa, e un PK composito in essa, che PK è una combinazione dei 2 PK delle altre 2 tabelle.
In altre parole, se esiste una relazione M:M
tra le tabelle A
e B
, creiamo una tabella C
che ha una relazione 1:M
con entrambe le tabelle A
e B
"Graficamente", sarebbe simile a:
+---+ 1 M +---+ M 1 +---+
| A |------| C |------| B |
+---+ +---+ +---+
Con la tabella C
PK in qualche modo simile a questa:
+-----+
| C |
+-----+
| id | <-- C.id = A.id + B.id (i.e. combined/concatenated, not addition!)
+-----+
o in questo modo:
+-------+
| C |
+-------+
| a_id | <--|
+-------+ +-- composite PK instead
| b_id | <--| of concatenation (recommended)
+-------+
Una chiave primaria essenzialmente tagga una riga con un identificativo univoco. Questo può essere composto da una o più colonne in una riga, ma più comunemente ne usa una. Parte di ciò che rende questo utile è quando hai tabelle aggiuntive (come quella nel tuo scenario) puoi riferirti a questo valore in altre tabelle. Dal momento che è unico, posso guardare una colonna con HelloCity
univoco in un'altra tabella (ad esempio HelloCity
) e sapere immediatamente dove cercare nella tabella Utente per ottenere ulteriori informazioni sulla persona a cui la colonna fa riferimento.
Ad esempio, HelloCity
memorizza solo gli ID per l' User
e la City
. Perché? Perché sarebbe sciocco ri-registrare TUTTI i dati sulla City
e TUTTI i dati User
in un'altra tabella quando già li hai archiviati altrove. Il bello è che, ad esempio, l'utente deve aggiornare il suo DisplayName
per qualche motivo. Per fare ciò, è sufficiente cambiarlo in Utente. Ora, qualsiasi riga che fa riferimento all'utente restituisce istantaneamente il nuovo DisplayName
; altrimenti dovresti trovare ogni record usando il vecchio DisplayName
e aggiornarlo di conseguenza, che in database più grandi potrebbe richiedere una notevole quantità di tempo.
Nota che la chiave primaria è unica solo in quella specifica tabella - potresti teoricamente vedere lo stesso valore di chiave primaria nelle tue tabelle City
e User
(questo è particolarmente comune se stai usando semplici numeri interi come ID) ma il tuo database conoscerà il differenza in base alla relazione che costruisci tra le tabelle e alle tue dichiarazioni JOIN nelle tue query.
Un altro modo in cui i tasti primari aiutano è che hanno automaticamente un indice generato nelle loro colonne. Ciò aumenta le prestazioni nelle query in cui la clausola WHERE cerca nel valore della colonna chiave primaria. E poiché probabilmente ti riferirai a quella chiave primaria in altre tabelle, renderà anche quella ricerca più veloce.
Nel tuo modello di dati vedo alcune colonne che contengono già "Id". Senza conoscere il set di dati, mi auguro che questi abbiano già valori unici, quindi dovrebbe essere opportuno inserire un PK su questi. Se ricevi degli errori, ci sono probabilmente dei duplicati.
Torna alla tua domanda su HelloCity
- Entity Framework è un po 'schizzinoso quando si tratta di chiavi. Se vuoi davvero giocare sul sicuro, puoi generare automaticamente un ID univoco per ogni voce e chiamarlo buono. Questo ha senso perché è una relazione molti-a-molti, nel senso che qualsiasi combinazione può apparire un numero qualsiasi di volte, quindi in teoria non esiste un modo affidabile per distinguere tra voci univoche. Nel caso in cui si desideri eliminare una singola voce in futuro, come sapresti a quale riga far riferimento? Si può fare l'argomento che si cerca su tutti i campi e il saluto può essere diverso, ma se ci sono più visite in una città con lo stesso saluto, si può casualmente perdere tutti quei record invece di uno solo.
Tuttavia, se si trattasse di una relazione uno-a-uno, si potrebbe fare a meno di rendere la combinazione di CityId
e UserId
la chiave primaria, poiché tale combinazione dovrebbe sempre essere univoca (perché non si dovrebbero mai vedere più righe che fanno la stessa combinazione).