在StackOverflow克隆中,“注释”表与“问题与解答”之间应该有什么关系?

时间:2009-06-12 16:29:10

标签: database database-design polymorphic-associations

在我正在构建的类似于StackOverflow的应用程序中,我正在尝试确定我的QuestionsAnswersComments表应该具有什么关系。

我可以让QuestionsAnswers都由一个表Posts表示。

这将允许Comments拥有Posts的单个外键。

但如果QuestionsAnswers是不同的表格,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
  );

6 个答案:

答案 0 :(得分:17)

我会选择Posts方法。这是确保参照完整性的最佳方法。

如果您需要分别为Answers和Questions添加其他列,请将它们放在与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建模继承:“Inheritance in relational databases。”

使用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哲学倾向于将数据模型的实施放入应用程序层。但是,如果没有约束强制数据库中的完整性,您就有可能存在应用程序中的错误或查询工具的即席查询会损害数​​据完整性的风险。

答案 1 :(得分:4)

在我建立的社交网络中,我做了一些不同的事情。如果您考虑一下,评论可以附加到网站中的任何实体。这可以是博客文章,论坛帖子或帖子,文章,某人图片,人物简介,服务供应商等。为此我创建了一个包含对象类型(表引用)的SystemObjects表。在大多数情况下,我为我的系统的实体创建了接受注释的记录......但是这些实体直接映射到我的表。 SystemObjects表包含SystemObjectID,以及用于将来引用的友好名称(查找表)。

有了这个我然后创建一个Comment表,它有SystemObjectID引用,告诉我要查看的表。然后我还有SystemObjectRecordID,它告诉我我感兴趣的引用表的哪个PK(以及所有标准评论数据)。

我将SystemObject表的这个概念用于我网站中的许多其他通用远景概念。想想标签,评级,评论以及可能在您的网站上附加的任何其他悬挂水果,并汇总以便快速使用。

在我的书ASP.NET 3.5 Social Networking中了解更多相关信息。

答案 2 :(得分:2)

您可以使用两个外键创建一个注释表,一个用于questions.questionID,另一个用于answers.answerId

答案 3 :(得分:1)

您需要两个将这些关系结合在一起的域表:CommentsForQuestions和CommentsForAnswers。基本上你需要为此目的创建5个表:

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

这有一个问题是它不如帖子的想法,因为参照完整性不那么强。我可以认为CommentsForQuestions连接到评论和问题,但我不能阻止问题和答案连接到相同的评论。

答案 4 :(得分:1)

外键关系;你可以有QuestionComments和AnswerComments,或者你可以让评论有问题和答案的外键列(并且这些列是独家的)。

就个人而言,我会采用邮政方式。

编辑:考虑到,第三种方法可行;你可能有一个评论表,然后只有一个关联表,将评论与问题或答案相关联(因此评论将有一个ID和评论,连接表将有一个CommentID,一个AnswerID和一个QuestionID )。或者,您可以只有一个Comments表,然后有一个Answer-Comment关联表和一个单独的Question-Comment关联表。

答案 5 :(得分:1)

我有两种方法可以想到。

首先,使用Comment表中的另一列来指示评论是属于问题还是答案。因此,Comment表的PK变成了PostID是问题或答案的外键,PostType可以是1 = Question和2 = Answer。

其次,为每个问答使用关系表。所以你有一个问题,答案,评论,问题评论和答案评论表。

假设问题,答案,评论表的主键分别是QuestionID,AnswerID和CommentID。那么QuestionComment的列将是[QuestionID,CommentID]。同样,AnswerComment的列将是[AnswerID,CommentID]。