44

Ich habe folgenden Kommentar Tabelle in meiner App:MySQL - Bedingte Foreign Key Constraints

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

die Idee dieser Tabelle ist Kommentare für verschiedene Teile meiner App speichern - es kann speichern Kommentare zu Blog-Post dh:

1|34|blogpost|lorem ipsum... 

user picture:

2|12|picture|lorem ipsum... 

und so weiter.

Gibt es jetzt eine Möglichkeit, die FOREIGN KEY-Einschränkung für solche Daten zu erzwingen?

das heißt so etwas wie dies in den Kommentaren Tabelle:

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

Antwort

71

Sie versuchen, ein Design zu tun, die Polymorphe Verbände genannt wird. Das heißt, der Fremdschlüssel kann Zeilen in irgendeiner von mehreren verwandten Tabellen referenzieren.

Ein Fremdschlüssel muss jedoch genau auf eine Tabelle verweisen. Sie können einen Fremdschlüssel, der auf andere Tabellen verweist, nicht abhängig von dem Wert in einer anderen Spalte Ihrer Comments-Tabelle deklarieren. Dies würde gegen mehrere Regeln des relationalen Datenbankentwurfs verstoßen.

Eine bessere Lösung ist es, eine Art "übersteuerbar" zu machen, auf die die Kommentare verweisen.

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) 
); 

Jeder Ihrer Inhaltstypen würde als Untertyp dieses Supertables betrachtet werden. Dies ist analog zu dem objektorientierten Konzept einer Schnittstelle.

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) 
); 

Bevor Sie eine Zeile in BlogPosts oder UserPictures einfügen können, müssen Sie eine neue Zeile Commentable legen Sie eine neue pseudokey-ID zu erzeugen. Dann können Sie diese generierte ID verwenden, wenn Sie den Inhalt in die entsprechende Untertypentabelle einfügen.

Sobald Sie all dies getan haben, können Sie sich auf referenzielle Integritätsbedingungen verlassen.

+1

Ich nehme an, UserPictures enthält ein Feld user_id, das auf die Benutzertabelle verweist. Wie behandeln Sie einen User-Löschvorgang so, dass der Löschvorgang in die Commentable-Tabelle übergeht? Ich habe diese Frage hier gestellt - http://stackoverflow.com/questions/11497149/how-to-enforce-referential-integrity-on-single-table-inheritance- und wäre Ihnen dankbar, wenn Sie mir erklären könnten, wie Sie damit umgehen Schluckauf, ich bleibe stecken. –

+13

@MattMcCormick, ich beantworte keine Fragen mehr zu SO, weil die anstößigen Moderatoren es sich nicht leisten konnten teilzunehmen. –

+2

Oh ok. Danke für deine Teilnahme in der Vergangenheit. Ich habe einige Ihrer Antworten zur Vererbung von einzelnen Tabellen und zu polymorphen Assoziationen gelesen und habe mir auch die Folien aus Ihrem Vortrag angeschaut, auf die Sie in einem von ihnen verwiesen haben. Es half mir, Situationen mit der Datenbank besser zu identifizieren, die zu Problemen auf der Straße führen könnten. Ich habe Ihr Buch zu meiner Leseliste hinzugefügt und werde es wahrscheinlich für mein nächstes Software-Buch abholen. –