В каком клоне StackOverflow какое отношение должна иметь таблица комментариев к Вопросам и Ответам? - PullRequest
12 голосов
/ 12 июня 2009

В приложении, похожем на StackOverflow, которое я создаю, я пытаюсь решить, какие отношения должны иметь мои таблицы Questions, Answers и Comments.

Я мог бы Questions и Answers оба быть представлены одной таблицей Posts.

Это позволило бы Comments иметь один внешний ключ для Posts.

Но если Questions и Answers являются отдельными таблицами, какие отношения Comments должны иметь к каждой из них?

ОБНОВЛЕНИЕ: Хотя выбранный ответ рекомендует подход наследования таблиц классов, и это кажется лучшим подходом в терминах базы данных, этот вариант не поддерживается 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
  );

Ответы [ 6 ]

17 голосов
/ 12 июня 2009

Я бы пошел с подходом сообщений. Это лучший способ обеспечить ссылочную целостность.

Если вам нужны дополнительные столбцы для Ответов и Вопросов соответственно, поместите их в дополнительные таблицы с отношением один к одному с сообщениями.

Например, в синтаксисе 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 выше. Вы можете использовать ограничения CHECK, чтобы применить значения в post_type, или использовать триггер, если ваша база данных не поддерживает ограничения CHECK.

Я также сделал презентацию, которая может вам помочь. Слайды на http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back. Вы должны прочитать разделы о Полиморфных Ассоциациях и Entity-Attribute-Value.


Если вы используете наследование отдельных таблиц, как вы сказали, что используете 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; 

В этом примере вы можете использовать ограничение внешнего ключа, и я рекомендую вам это сделать! : -)

Философия Rails способствует внедрению модели данных на прикладном уровне. Но без ограничений, обеспечивающих целостность в базе данных, вы рискуете, что ошибки в вашем приложении или специальные запросы из инструмента запросов могут нанести ущерб целостности данных.

4 голосов
/ 12 июня 2009

В социальных сетях, которые я создаю, я делаю что-то немного другое. Если вы думаете об этом, комментарий может быть прикреплен практически к любому объекту на сайте. Это может быть сообщение в блоге, ветка или сообщение на форуме, статья, чья-то фотография, личный профиль, поставщик услуги и т. Д. По этой причине я создаю таблицу SystemObjects, которая содержит тип объекта (ссылка на таблицу). По большей части я создаю записи для сущностей моей системы, которые будут принимать комментарии ... но они отображаются непосредственно в мои таблицы. Таблица SystemObjects содержит SystemObjectID и понятное имя для использования в будущем (справочная таблица).

После этого я создаю таблицу Comments, которая имеет ссылку SystemObjectID, чтобы указать мне, в какую таблицу обращаться. Затем я также размещаю SystemObjectRecordID, который сообщает мне, какой PK указанной таблицы мне интересен (наряду с все стандартные данные комментариев).

Я использую это понятие таблицы SystemObject для многих других общих далеко идущих концепций на моих сайтах. Подумайте о тегах, рейтингах, комментариях и любых других висячих фруктах, которые могут быть прикреплены к вашему сайту и объединены для быстрого использования.

Подробнее об этом читайте в моей книге Социальные сети ASP.NET 3.5 .

2 голосов
/ 12 июня 2009

Вы можете создать одну таблицу комментариев с двумя внешними ключами, один для questions.questionID, а другой для answers.answerId

1 голос
/ 12 июня 2009

Есть два способа, о которых я могу думать.

Сначала используйте другой столбец в таблице комментариев, чтобы указать, принадлежит ли комментарий к вопросу или ответу. Таким образом, PK таблицы Комментариев становится таким, когда PostID является внешним ключом к Вопросу или Ответу, а PostType может выглядеть примерно так: 1 = Вопрос и 2 = Ответ.

Во-вторых, используйте таблицу отношений для каждого Вопроса и Ответа. Итак, у вас есть таблица вопросов, ответов, комментариев, вопросов и ответов.

Предположим, что первичным ключом таблиц Вопроса, Ответа, Комментария являются ИД вопроса, Ответ и ИД, соответственно. Тогда столбцы QuestionComment будут иметь вид [QuestionID, CommentID]. Аналогично, столбцы AnswerComment будут иметь вид [AnswerID, CommentID].

1 голос
/ 12 июня 2009

отношение внешнего ключа; у вас могут быть вопросы QuestionComments и AnswerComments или комментарии, имеющие столбец внешнего ключа для вопросов и ответов (и эти столбцы должны быть эксклюзивными).

Лично я бы пошел с подходом Постов.

Редактировать: на рассмотрение, есть третий подход, который может работать; у вас может быть таблица комментариев, а затем просто таблица ассоциации, которая связывает комментарии либо с вопросом, либо с ответом (таким образом, комментарии будут иметь идентификатор и комментарий, а таблица соединения будет иметь комментарий, идентификатор ответа и вопрос, ). Или вы можете иметь только таблицу комментариев, затем таблицу сопоставления с комментарием и отдельную таблицу сопоставления с комментарием вопроса.

1 голос
/ 12 июня 2009

Вам понадобятся две таблицы доменов, которые объединяют отношения CommentsForQuestions и CommentsForAnswers. Для этого вам нужно создать 5 таблиц:

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

Единственная проблема, с которой это связано, заключается в том, что она уступает идее постов, потому что ссылочная целостность не так сильна. Я могу гарантировать, что CommentsForQuestions соединяется с комментарием и вопросом, но я не могу помешать соединению вопроса и ответа к одному и тому же комментарию.

...