एक विदेशी कुंजी में केवल एक मूल तालिका का संदर्भ होना चाहिए। यह SQL सिंटैक्स और रिलेशनल सिद्धांत दोनों के लिए मौलिक है।
एक पॉलीमॉर्फिक एसोसिएशन तब होता है जब किसी दिए गए कॉलम में दो या दो से अधिक मूल तालिकाओं का संदर्भ हो सकता है। कोई रास्ता नहीं है कि आप SQL में उस बाधा की घोषणा कर सकते हैं।
पॉलिमॉर्फिक एसोसिएशन डिज़ाइन रिलेशनल डेटाबेस डिज़ाइन के नियमों को तोड़ता है। मैं इसका उपयोग करने की सलाह नहीं देता।
कई विकल्प हैं:
विशिष्ट आर्क: कई विदेशी कुंजी कॉलम बनाएँ, प्रत्येक एक माता-पिता को संदर्भित करता है। लागू करें कि इनमें से कोई एक विदेशी कुंजी गैर-पूर्ण हो सकती है।
रिलेशनशिप को उल्टा करें : तीन कई-से-कई तालिकाओं का उपयोग करें, प्रत्येक संदर्भ टिप्पणियाँ और एक संबंधित माता-पिता।
कंक्रीट सुपरटेबल: निहित "टिप्पणी योग्य" सुपरक्लास के बजाय, एक वास्तविक तालिका बनाएं जो आपके प्रत्येक माता-पिता तालिकाओं का संदर्भ दें। फिर अपनी टिप्पणियों को उस सुपरटेबल से लिंक करें। छद्म रेल कोड कुछ इस तरह होगा (मैं एक रेल उपयोगकर्ता नहीं हूं, इसलिए इसे एक दिशानिर्देश के रूप में मानें, न कि शाब्दिक कोड के रूप में):
class Commentable < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :commentable
end
class Article < ActiveRecord::Base
belongs_to :commentable
end
class Photo < ActiveRecord::Base
belongs_to :commentable
end
class Event < ActiveRecord::Base
belongs_to :commentable
end
मैं अपनी प्रस्तुति में पॉलीमॉर्फिक एसोसिएशनों को एसक्यूएल में प्रैक्टिकल ऑब्जेक्ट-ओरिएंटेड मॉडल , और मेरी पुस्तक एसक्यूएल एंटीपैर्टन्स: डेटाबेस प्रोग्रामिंग के नुकसान से बचता हूं ।
अपनी टिप्पणी को फिर से लिखें: हाँ, मुझे पता है कि एक और स्तंभ है जो उस तालिका का नाम नोट करता है जिसे विदेशी कुंजी माना जाता है। यह डिज़ाइन SQL में विदेशी कुंजियों द्वारा समर्थित नहीं है।
उदाहरण के लिए, यदि आप एक टिप्पणी और नाम "वीडियो" सम्मिलित करते हैं, तो उसके लिए मूल तालिका का नाम Comment
क्या है ? "वीडियो" नाम की कोई तालिका मौजूद नहीं है। क्या सम्मिलित त्रुटि के साथ गर्भपात किया जाना चाहिए? किस बाधा का उल्लंघन किया जा रहा है? RDBMS को कैसे पता चलता है कि इस स्तंभ को किसी मौजूदा तालिका का नाम देना है? यह केस-असंवेदनशील तालिका नामों को कैसे संभालता है?
इसी तरह, यदि आप Events
तालिका को छोड़ देते हैं, लेकिन आपके पास पंक्तियाँ हैं Comments
जो ईवेंट को उनके माता-पिता के रूप में इंगित करती हैं, तो परिणाम क्या होना चाहिए? क्या ड्रॉप टेबल को निरस्त किया जाना चाहिए? पंक्तियों को Comments
अनाथ होना चाहिए ? क्या उन्हें किसी अन्य मौजूदा तालिका जैसे कि को बदलना चाहिए Articles
? क्या उस आईडी वैल्यू को इंगित करते हैं Events
जो किसी ओर इशारा करते समय कोई मतलब निकालने के लिए इस्तेमाल करती है Articles
?
ये दुविधाएं इस तथ्य के कारण हैं कि पॉलिमॉर्फिक एसोसिएशन मेटाडेटा (एक तालिका नाम) को संदर्भित करने के लिए डेटा (यानी एक स्ट्रिंग मूल्य) का उपयोग करने पर निर्भर करता है। यह SQL द्वारा समर्थित नहीं है। डेटा और मेटाडेटा अलग-अलग हैं।
मुझे आपके "कंक्रीट सुपरटेबल" प्रस्ताव के चारों ओर अपना सिर लपेटने में मुश्किल समय हो रहा है।
Commentable
एक वास्तविक एसक्यूएल तालिका के रूप में परिभाषित करें , न केवल आपके रेल मॉडल परिभाषा में एक विशेषण। कोई अन्य कॉलम आवश्यक नहीं है।
CREATE TABLE Commentable (
id INT AUTO_INCREMENT PRIMARY KEY
) TYPE=InnoDB;
तालिकाओं को परिभाषित करें Articles
, Photos
और Events
"उपवर्गों" के रूप में की Commentable
है, उनके प्राथमिक कुंजी भी एक विदेशी कुंजी संदर्भित होना बनाकर Commentable
।
CREATE TABLE Articles (
id INT PRIMARY KEY,
FOREIGN KEY (id) REFERENCES Commentable(id)
) TYPE=InnoDB;
Comments
एक विदेशी कुंजी के साथ तालिका को परिभाषित करें Commentable
।
CREATE TABLE Comments (
id INT PRIMARY KEY AUTO_INCREMENT,
commentable_id INT NOT NULL,
FOREIGN KEY (commentable_id) REFERENCES Commentable(id)
) TYPE=InnoDB;
जब आप Article
(उदाहरण के लिए) बनाना चाहते हैं , तो आपको एक नई पंक्ति Commentable
भी बनानी होगी । तो भी के लिए Photos
और Events
।
INSERT INTO Commentable (id) VALUES (DEFAULT);
INSERT INTO Articles (id, ...) VALUES ( LAST_INSERT_ID(), ... );
INSERT INTO Commentable (id) VALUES (DEFAULT);
INSERT INTO Photos (id, ...) VALUES ( LAST_INSERT_ID(), ... );
INSERT INTO Commentable (id) VALUES (DEFAULT);
INSERT INTO Events (id, ...) VALUES ( LAST_INSERT_ID(), ... );
जब आप एक बनाना चाहते हैं Comment
, तो उस मान का उपयोग करें जो मौजूद है Commentable
।
INSERT INTO Comments (id, commentable_id, ...)
VALUES (DEFAULT, 2, ...);
जब आप किसी दिए गए टिप्पणियों की क्वेरी करना चाहते हैं Photo
, तो कुछ सम्मिलित करें:
SELECT * FROM Photos p JOIN Commentable t ON (p.id = t.id)
LEFT OUTER JOIN Comments c ON (t.id = c.commentable_id)
WHERE p.id = 2;
जब आपके पास केवल एक टिप्पणी की आईडी होती है और आप यह जानना चाहते हैं कि यह किस उल्लेखनीय संसाधन के लिए टिप्पणी है। इसके लिए, आप पा सकते हैं कि यह उल्लेखनीय तालिका के लिए उपयोगी है कि यह किस संसाधन को संदर्भित करता है।
SELECT commentable_id, commentable_type FROM Commentable t
JOIN Comments c ON (t.id = c.commentable_id)
WHERE c.id = 42;
फिर आपको संबंधित संसाधन तालिका (फ़ोटो, लेख, आदि) से डेटा प्राप्त करने के लिए दूसरी क्वेरी को चलाने की आवश्यकता है, जिसके बाद पता चलता है commentable_type
कि किस तालिका से जुड़ना है। आप इसे उसी क्वेरी में नहीं कर सकते, क्योंकि एसक्यूएल की आवश्यकता है कि तालिकाओं को स्पष्ट रूप से नामित किया जाए; आप उसी क्वेरी में डेटा परिणामों द्वारा निर्धारित तालिका में शामिल नहीं हो सकते।
बेशक, इन चरणों में से कुछ रेल द्वारा उपयोग किए गए सम्मेलनों को तोड़ते हैं। लेकिन उचित रिलेशनल डेटाबेस डिज़ाइन के संबंध में रेल कन्वेंशन गलत हैं।
foreign_key
विकल्प के बारे में बात नहीं कर रहा है जिसे पारित किया जा सकता हैbelongs_to
। ओपी मूल डेटाबेस के एक "विदेशी कुंजी बाधा" के बारे में बात कर रहा है। इसने मुझे थोड़ी देर के लिए उलझन में डाल दिया।