В клон StackOverflow, какая связь должна иметь таблица комментариев в вопросах и ответах?
В приложении, аналогичном StackOverflow, который я создаю, я пытаюсь решить, какие отношения должны иметь таблицы Questions
, Answers
и Comments
.
Я мог бы иметь Questions
и Answers
обе быть представлены одной таблицей Posts
.
Это позволит Comments
иметь один внешний ключ для Posts
.
Но если Questions
и Answers
являются отдельными таблицами, какие отношения должны Comments
иметь к каждому из них?
ОБНОВЛЕНИЕ. Хотя выбранный ответ рекомендует использовать метод наследования класса таблицы, и это похоже на лучший подход в терминах базы данных, этот параметр не поддерживается ORM Rails. Итак, в 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
);
Ответы
Ответ 1
Я бы пошел с подходом Posts. Это лучший способ обеспечить ссылочную целостность.
Если вам нужны дополнительные столбцы для ответов и вопросов соответственно, поместите их в дополнительные таблицы с отношениями "один к одному" с 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 имеет тенденцию способствовать внедрению модели данных в прикладной уровень. Но без ограничений, обеспечивающих целостность в базе данных, вы рискуете, что ошибки в вашем приложении или специальные запросы из инструмента запроса могут повредить целостность данных.
Ответ 2
В социальных сетях, которые я создаю, я делаю что-то совсем другое. Если вы думаете об этом, комментарий может быть прикреплен к любому сущности на сайте. Это может быть сообщение в блоге, поток или сообщение форума, статья, изображение someones, профиль лиц, поставщик сервиса и т.д. По этой причине я создаю таблицу SystemObjects, которая содержит тип объекта (ссылка на таблицу). По большей части я создаю записи для сущностей моей системы, которые будут принимать комментарии... но они отображаются непосредственно в мои таблицы. В таблице SystemObjects находится SystemObjectID и дружественное имя для ссылки в будущем (таблица поиска).
С этим на месте я создаю таблицу комментариев, в которой есть ссылка SystemObjectID, чтобы рассказать мне, в какую таблицу искать. Затем я также размещаю SystemObjectRecordID, который сообщает мне, какой PK таблицы, на которую я заинтересован (вместе с все стандартные данные комментариев).
Я использую это понятие таблицы SystemObject для многих других общих далеко идущих концепций на своих сайтах. Подумайте о тегах, рейтингах, комментариях и любых других висящих фруктах, которые могут быть прикреплены на вашем сайте и объединены для быстрого использования.
Подробнее об этом читайте в моей книге ASP.NET 3.5 Социальные сети.
Ответ 3
Вы можете создать одну таблицу комментариев с двумя внешними ключами, один для вопросов .questionID, а другой - для answer.answerId
Ответ 4
Вам понадобятся две таблицы домена, которые связывают отношения вместе с комментариями ForQuestions и CommentsForAnswers. В основном вам понадобится создать 5 таблиц для этой цели:
Questions
Answers
Comments
CommentsForQuestions (relates comments to questions)
CommentsForAnswers (relates comments to answers)
Единственная проблема заключается в том, что она уступает идее сообщений, поскольку ссылочная целостность не такая сильная. Я могу гарантировать, что комментарииForQuestions соединяются с комментарием и вопросом, но я не могу предотвратить вопрос и ответ от подключения к тому же комментарию.
Ответ 5
Отношение внешних ключей; вы можете либо иметь комментарии и комментарии, либо иметь комментарии в столбце "Внешний ключ" для обоих вопросов и ответов (и чтобы эти столбцы были эксклюзивными).
Лично я бы пошел с подходом Posts.
Изменить: при рассмотрении есть третий подход, который может работать; у вас может быть таблица комментариев, а затем просто есть таблица ассоциаций, которая связывает комментарии с вопросом или ответом (так что комментарии будут иметь идентификатор и комментарий, в таблице соединений будут ID CommentID, AnswerID и QuestionID). Или вы могли бы иметь только таблицу комментариев, а затем иметь таблицу ассоциации "Комментарий к комментарию" и отдельную таблицу ассоциаций вопросов и комментариев.
Ответ 6
Есть два способа, о которых я могу думать.
Сначала используйте другой столбец в таблице комментариев, чтобы указать, принадлежит ли комментарий к Вопросу или Ответу. Таким образом, ПК таблицы комментариев становится wher PostID - это внешний ключ для вопроса или ответа, а PostType может быть примерно 1 = Вопрос и 2 = Ответ.
Во-вторых, используйте таблицу отношений для каждого вопроса и ответа. Таким образом, у вас есть таблица вопросов, ответов, комментариев, вопросов и комментариев.
Предположим, что первичным ключом таблиц "Вопрос", "Ответ", "Комментарий" является "QuestionID", "ReplyID" и "CommentID" соответственно. Тогда столбцы QuestionComment будут [QuestionID, CommentID]. Аналогично, столбцы AnswerComment будут [answerID, CommentID].