44

devo seguente tabella 'commenti' nella mia app:MySQL - condizionali vincoli di chiave esterna

comments 
-------- 
id   INT 
foreign_id INT 
model  TEXT 
comment_text TEXT 
... 

l'idea di questa tabella è quello di memorizzare commenti per varie parti del mio app - è in grado di memorizzare commenti per post sul blog vale a dire: foto

1|34|blogpost|lorem ipsum... 

utente:

2|12|picture|lorem ipsum... 

e così via.

ora, c'è un modo per forzare il vincolo FOREIGN KEY su tali dati?

vale a dire una cosa del genere nella tabella commenti:

FOREIGN KEY (`foreign_id`) REFERENCES blogposts (`id`) 
//but only when model='blogpost' 

risposta

71

si sta tentando di fare un disegno che si chiama polimorfiche Associazioni. Cioè, la chiave esterna può fare riferimento a righe in una qualsiasi delle varie tabelle correlate.

Ma un vincolo di chiave esterna deve fare riferimento esattamente a una tabella. Non è possibile dichiarare una chiave esterna che fa riferimento a tabelle diverse a seconda del valore in un'altra colonna della tabella Comments. Ciò violerebbe diverse regole della progettazione del database relazionale.

Una soluzione migliore è rendere una sorta di "superfluo" a cui fanno riferimento i commenti.

CREATE TABLE Commentable (
    id SERIAL PRIMARY KEY 
); 

CREATE TABLE Comments (
    comment_id SERIAL PRIMARY KEY, 
    foreign_id INT NOT NULL, 
    ... 
    FOREIGN KEY (foreign_id) REFERENCES Commentable(id) 
); 

Ciascuno dei tipi di contenuto sarebbe considerato un sottotipo di questo superabile. Questo è analogo al concetto orientato agli oggetti di un'interfaccia .

CREATE TABLE BlogPosts (
    blogpost_id INT PRIMARY KEY, -- notice this is not auto-generated 
    ... 
    FOREIGN KEY (blogpost_id) REFERENCES Commentable(id) 
); 

CREATE TABLE UserPictures (
    userpicture_id INT PRIMARY KEY, -- notice this is not auto-generated 
    ... 
    FOREIGN KEY (userpicture_id) REFERENCES Commentable(id) 
); 

Prima di poter inserire una riga nella BlogPosts o UserPictures, è necessario inserire una nuova riga per Commentable per generare un nuovo pseudokey id. Quindi puoi usare quell'ID generato mentre inserisci il contenuto nella rispettiva tabella del sottotipo.

Una volta fatto tutto ciò, è possibile fare affidamento sui vincoli di integrità referenziale.

+1

Presumo che UserPictures contenga un campo user_id che fa riferimento alla tabella Utente. Come gestisci l'eliminazione di un utente in modo tale che l'eliminazione si sovrapponga alla tabella Commentabile? Ho posto questa domanda qui - http://stackoverflow.com/questions/11497149/how-to-enforce-referential-integrity-on-single-table-inheritance - e sarei grato se potessi spiegare come gestisci questo singhiozzo mi sto bloccando. –

+13

@MattMcCormick, non rispondo più alle domande su SO, perché gli odiosi moderatori hanno reso inutile la partecipazione. –

+2

Oh ok. Grazie per la tua partecipazione passata. Ho letto un bel po 'delle tue risposte riguardanti l'ereditarietà di una tabella singola e le associazioni polimorfiche e ho anche guardato le diapositive dei tuoi discorsi a cui ti riferivi in ​​uno di essi. Mi ha aiutato a identificare meglio le situazioni con il database che potrebbero portare a problemi lungo la strada. Ho aggiunto il tuo libro alla mia lista di lettura e probabilmente lo raccoglierò per il mio prossimo libro di software da leggere. –

Problemi correlati