В клоне StackOverflow какое отношение должна иметь таблица комментариев к вопросам и ответам?

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

Вопрос

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

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

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

Но если Questions и Answers это отдельные таблицы, какие связи должны Comments придется каждому из них?

ОБНОВЛЯТЬ:Хотя выбранный ответ рекомендует подход наследования таблицы классов, и это кажется лучшим подходом с точки зрения базы данных, этот вариант не поддерживается Rails ORM.Итак, в Rails мои модели должны будут использовать наследование одной таблицы и, вероятно, будут выглядеть так:

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
  );
Это было полезно?

Решение

Я бы выбрал подход Posts.Это лучший способ обеспечить ссылочную целостность.

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

Например, в синтаксисе 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.Вам следует прочитать разделы «Полиморфные ассоциации» и «Значение атрибута сущности».


Если вы используете наследование одной таблицы, как вы сказали, вы используете 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 склоняется к тому, чтобы реализовать модель данных на уровне приложения.Но без ограничений, обеспечивающих целостность базы данных, вы рискуете, что ошибки в вашем приложении или специальные запросы инструмента запросов могут нанести ущерб целостности данных.

Другие советы

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

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

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

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

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

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

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

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

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

Лично я бы выбрал подход Posts.

Редактировать:Если подумать, есть третий подход, который может сработать;у вас может быть таблица комментариев, а затем просто таблица связей, которая связывает комментарии либо с вопросом, либо с ответом (поэтому комментарии будут иметь идентификатор и комментарий, а таблица соединений будет иметь CommentID, AnswerID и QuestionID ).Или вы можете иметь только таблицу «Комментарии», затем таблицу связей «Ответ-комментарий» и отдельную таблицу связей «Вопрос-комментарий».

Я могу придумать два способа.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top