在 StackOverflow 克隆中,评论表与问题和答案应该有什么关系?
-
13-09-2019 - |
题
在我正在构建的类似于 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
);
解决方案
我会采用帖子方法。这是确保引用完整性的最佳方法。
如果您分别需要答案和问题的附加列,请将它们放入与帖子具有一对一关系的附加表中。
例如,在 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社交网络
您可以创建一个单独的意见表,两个外键,一到questions.questionID,另一个answers.answerId
您将需要带来的关系一起CommentsForQuestions和CommentsForAnswers二级域名表。基本上,你将需要创建5台用于此目的:
Questions
Answers
Comments
CommentsForQuestions (relates comments to questions)
CommentsForAnswers (relates comments to answers)
在一个问题这已经是它的劣于岗位的想法,因为参照完整性是没有那么强。我可以garuntee是CommentsForQuestions连接到评论和问题,但我不能阻止这两个问题,并从连接到同一个注释的答案。
一个外键关系;你可以有QuestionComments和AnswerComments,或者你可以有意见有两个问题与解答一个外键列(并有那些列是唯一的)。
个人而言,我去与柱的方法。
编辑:在考虑,有一个可能的工作第三种方法;你可能有一个意见表,然后只是有注释与任何一个问题或答案关联的关联表(这样的评论将有一个ID和注释,连接表将有一个CommentID,一个AnswerID和QuestionID )。或者,你可以有只是一个意见表,然后有一个答案,评论关联表,和一个单独的问题,评论关联表。
有2种方式,我能想到的。
首先,使用另一列在注释表以指示注释是否属于问题或答案。所以注释表的PK变得wher是帖子ID的外键的问题或答案以及PostType可以成才样1 =问题和2 =回答。
其次,使用一个关系表针对每个问题与答案。所以,你有一个问题,答案,评论,QuestionComment和AnswerComment表。
让我们说的问题,答案的主键,评论表是QuestionID,AnswerID和CommentID分别。然后QuestionComment的列将是[QuestionID,CommentID]。类似地,AnswerComment的列将是[AnswerID,CommentID]。