في استنساخ StackOverflow، ما هي العلاقة التي يجب أن تربط جدول التعليقات بالأسئلة والأجوبة؟

StackOverflow https://stackoverflow.com/questions/987654

سؤال

في تطبيق مشابه لـ StackOverflow الذي أقوم بإنشائه، أحاول تحديد العلاقة التي تربطني Questions, Answers و Comments ينبغي أن يكون للجداول.

يمكنني الحصول علي Questions و Answers كلاهما يتم تمثيلهما بجدول واحد Posts.

وهذا من شأنه أن يسمح Comments أن يكون لديك مفتاح خارجي واحد ل Posts.

لكن اذا Questions و Answers هي جداول منفصلة، ​​ما ينبغي أن العلاقات Comments يجب على كل من هذه؟

تحديث:على الرغم من أن الإجابة المختارة توصي باتباع نهج Class Table Inheritance ويبدو أن هذا هو أفضل نهج من حيث قواعد البيانات، إلا أن هذا الخيار غير مدعوم من قبل Rails ORM.لذلك، في Rails، سيتعين على النماذج الخاصة بي استخدام Single Table Inheritance ومن المحتمل أن تبدو كما يلي:

class Post < ActiveRecord::Base  
end  

class Question < Post  
  has_many :answers, :foreign_key => :parent_id  
  has_many :comments, :foreign_key => :parent_id  
end  

class Answer < Post  
  belongs_to :question, :foreign_key => :parent_id  
  has_many :comments, :foreign_key => :parent_id  
end  

class Comment < Post  
  belongs_to :question, :foreign_key => :parent_id  
  belongs_to :answer, :foreign_key => :parent_id  
end


class CreatePosts < ActiveRecord::Migration  
    def self.up  
      create_table :posts do |t|  
        t.string :type 
        t.string :author   
        t.text :content  
        t.integer :parent_id   
        t.timestamps  
      end  
    end  


    def self.down  
      drop_table :posts  
    end  
end
CREATE TABLE "posts" (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,  
  "type" varchar(255),  
  "author" varchar(255),  
  "content" text,  
  "parent_id" integer,  
  "created_at" datetime, 
  "updated_at" datetime
  );
هل كانت مفيدة؟

المحلول

سأتبع نهج المشاركات.هذه هي أفضل طريقة لضمان التكامل المرجعي.

إذا كنت بحاجة إلى أعمدة إضافية للإجابات والأسئلة على التوالي، فضعها في جداول إضافية ذات علاقة رأس برأس مع المنشورات.

على سبيل المثال، في بناء جملة MySQL:

CREATE TABLE Posts (
  post_id     SERIAL PRIMARY KEY,
  post_type   CHAR(1),              -- must be 'Q' or 'A'
  -- other columns common to both types of Post
  UNIQUE KEY (post_id, post_type) -- to support foreign keys
) ENGINE=InnoDB;

CREATE TABLE Comments (
  comment_id  SERIAL PRIMARY KEY, 
  post_id     BIGINT UNSIGNED NOT NULL,
  -- other columns for comments (e.g. date, who, text)
  FOREIGN KEY (post_id) REFERENCES Posts(post_id)
) ENGINE=InnoDB; 

CREATE TABLE Questions (
  post_id     BIGINT UNSIGNED PRIMARY KEY,
  post_type   CHAR(1),              -- must be 'Q'
  -- other columns specific to Questions
  FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
) ENGINE=InnoDB;

CREATE TABLE Answers (
  post_id     BIGINT UNSIGNED PRIMARY KEY,
  post_type   CHAR(1),              -- must be 'A'
  question_id BIGINT UNSIGNED NOT NULL,
  -- other columns specific to Answers
  FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
  FOREIGN KEY (question_id) REFERENCES Questions(post_id)
) ENGINE=InnoDB;

وهذا ما يسمى وراثة جدول الفصل.هناك نظرة عامة لطيفة على وراثة النمذجة باستخدام SQL في هذه المقالة:"الميراث في قواعد البيانات العلائقية."

قد يكون من المفيد استخدام post_type بحيث تكون المشاركة المحددة عبارة عن إجابة واحدة أو سؤال واحد فقط.لا تريد أن تشير كل من الإجابة والسؤال إلى مشاركة معينة.لذلك هذا هو الغرض من post_type العمود أعلاه.يمكنك استخدام قيود التحقق لفرض القيم post_type, أو استخدم مشغلًا إذا كانت قاعدة البيانات الخاصة بك لا تدعم قيود التحقق.

لقد قمت أيضًا بعمل عرض تقديمي قد يساعدك.الشرائح تصل إلى http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back.يجب عليك قراءة الأقسام الخاصة بالارتباطات متعددة الأشكال وقيمة سمة الكيان.


إذا كنت تستخدم Single Table Inheritance، كما قلت أنك تستخدم Ruby on Rails، فسيبدو SQL DDL كما يلي:

CREATE TABLE Posts (
  post_id     SERIAL PRIMARY KEY,
  post_type   CHAR(1),              -- must be 'Q' or 'A'
  -- other columns for both types of Post
  -- Question-specific columns are NULL for Answers, and vice versa.
) ENGINE=InnoDB;

CREATE TABLE Comments (
  comment_id  SERIAL PRIMARY KEY, 
  post_id     BIGINT UNSIGNED NOT NULL,
  -- other columns for comments (e.g. date, who, text)
  FOREIGN KEY (post_id) REFERENCES Posts(post_id)
) ENGINE=InnoDB; 

يمكنك استخدام قيد المفتاح الخارجي في هذا المثال، وأوصيك بذلك!:-)

تميل فلسفة ريلز إلى تفضيل تطبيق نموذج البيانات في طبقة التطبيق.ولكن بدون القيود التي تفرض التكامل في قاعدة البيانات، فإنك تتعرض لخطر أن تؤدي الأخطاء الموجودة في التطبيق الخاص بك، أو الاستعلامات المخصصة من أداة الاستعلام، إلى الإضرار بتكامل البيانات.

نصائح أخرى

في الشبكات الاجتماعية التي أقوم بإنشائها، أفعل شيئًا مختلفًا بعض الشيء.إذا فكرت في الأمر، فيمكن إرفاق تعليق بأي كيان في الموقع.يمكن أن يكون هذا منشورًا في مدونة، أو موضوعًا أو منشورًا في المنتدى، أو مقالًا، أو صورة لشخص ما، أو ملفًا شخصيًا لشخص ما، أو بائع خدمة، وما إلى ذلك.لهذا السبب أقوم بإنشاء جدول SystemObjects الذي يحتوي على نوع الكائن (مرجع الجدول).بالنسبة للجزء الأكبر، أقوم بإنشاء سجلات لكيانات نظامي التي ستقبل التعليقات... ولكن يتم تعيينها مباشرة إلى جداولي.يحتوي جدول SystemObjects على SystemObjectID واسم مألوف للرجوع إليه مستقبلاً (جدول بحث).

مع وضع هذا في مكانه، أقوم بعد ذلك بإنشاء جدول تعليقات يحتوي على مرجع SystemObjectID ليخبرني بالجدول الذي يجب أن أبحث فيه.ثم أقوم أيضًا بتضمين SystemObjectRecordID الذي يخبرني عن PK في الجدول المشار إليه الذي يهمني (إلى جانب جميع بيانات التعليق القياسية).

أستخدم فكرة جدول SystemObject للعديد من المفاهيم العامة الأخرى بعيدة المدى في مواقعي.فكر في العلامات والتقييمات والتعليقات وأي ثمار متدلية أخرى قد يتم إرفاقها عبر موقعك وتجميعها للاستخدام السريع.

اقرأ المزيد عن هذا في كتابي ASP.NET 3.5 الشبكات الاجتماعية.

يمكنك إنشاء جدول تعليقات واحد يحتوي على مفتاحين خارجيين، أحدهما لـ questions.questionID والآخر لـ Answers.answerId

ستحتاج إلى جدولي مجال يجمعان العلاقات معًا CommentsForQuestions وCommentsForAnswers.ستحتاج في الأساس إلى إنشاء 5 جداول لهذا الغرض:

Questions
Answers
Comments
CommentsForQuestions (relates comments to questions)
CommentsForAnswers (relates comments to answers)

المشكلة الوحيدة في هذا هي أنها أقل شأنا من فكرة المنشورات لأن التكامل المرجعي ليس قويا.يمكنني أن أضمن أن CommentsForQuestions يرتبط بتعليق وسؤال، لكن لا يمكنني منع سؤال وإجابة من الاتصال بنفس التعليق.

علاقة المفتاح الخارجي؛يمكنك إما الحصول على تعليقات الأسئلة وتعليقات الإجابة، أو يمكنك جعل التعليقات تحتوي على عمود مفتاح خارجي لكل من الأسئلة والأجوبة (وتكون هذه الأعمدة حصرية).

أنا شخصياً سأتبع نهج المشاركات.

يحرر:وبالنظر إلى ذلك، هناك نهج ثالث قد ينجح؛قد يكون لديك جدول تعليقات، ثم يكون لديك جدول اقتران يربط التعليقات إما بسؤال أو إجابة (بحيث تحتوي التعليقات على معرف والتعليق، وسيحتوي جدول الانضمام على معرف التعليق ومعرف الإجابة ومعرف السؤال ).أو، يمكن أن يكون لديك جدول تعليقات فقط، ثم يكون لديك جدول اقتران الإجابة والتعليق، وجدول اقتران سؤال وتعليق منفصل.

هناك طريقتان يمكنني التفكير فيهما.

أولاً، استخدم عمودًا آخر في جدول التعليق للإشارة إلى ما إذا كان التعليق ينتمي إلى سؤال أم إجابة.لذلك يصبح PK لجدول التعليق حيث يكون PostID هو المفتاح الخارجي للسؤال أو الإجابة ويمكن أن يكون PostType مثل 1=سؤال و2=إجابة.

ثانيًا، استخدم جدول العلاقات لكل سؤال وجواب.إذن لديك جدول سؤال وإجابة وتعليق وسؤال وتعليق وإجابة وتعليق.

لنفترض أن المفتاح الأساسي لجداول السؤال والإجابة والتعليق هو معرف السؤال ومعرف الإجابة ومعرف التعليق على التوالي.ثم ستكون أعمدة QuestionComment هي [QuestionID, CommentID].وبالمثل، ستكون أعمدة AnswerComment هي [AnswerID, CommentID].

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top