12

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

我可以有Questions并且Answers两者都由一个表表示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
  );
4

6 回答 6

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 建模继承:“关系数据库中的继承”。

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

于 2009-06-12T16:39:44.793 回答
4

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

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

我将 SystemObject 表的这个概念用于我的站点中的许多其他通用的、影响深远的概念。想想标签、评级、评论和任何其他可能附加在您的网站上并汇总起来以供快速使用的悬垂果实。

在我的书ASP.NET 3.5 Social Networking中阅读有关此内容的更多信息。

于 2009-06-12T16:43:57.310 回答
2

您可以创建一个带有两个外键的评论表,一个是 questions.questionID,另一个是 answers.answerId

于 2009-06-12T16:35:25.303 回答
1

您将需要两个域表,将关系组合在一起 CommentsForQuestions 和 CommentsForAnswers。基本上,您将需要为此创建 5 个表:

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

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

于 2009-06-12T16:31:08.510 回答
1

外键关系;您可以有 QuestionComments 和 AnswerComments,也可以让 Comments 有一个问题和答案的外键列(并且这些列是排他的)。

就个人而言,我会采用 Posts 方法。

编辑:在考虑中,有第三种方法可能有效;您可能有一个 Comments 表,然后只有一个关联表将 Comments 与 Question 或 Answer 相关联(因此 Comments 将具有 ID 和 comment,连接表将具有 CommentID、AnswerID 和 QuestionID )。或者,您可以只有一个 Comments 表,然后有一个 Answer-Comment 关联表和一个单独的 Question-Comment 关联表。

于 2009-06-12T16:31:50.227 回答
1

我能想到的方法有两种。

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

其次,为每个问题和答案使用关系表。因此,您有一个 Question、Answer、Comment、QuestionComment 和 AnswerComment 表。

假设 Question、Answer、Comment 表的主键分别是 QuestionID、AnswerID 和 CommentID。那么 QuestionComment 的列将是 [QuestionID, CommentID]。同样,AnswerComment 的列将是 [AnswerID, CommentID]。

于 2009-06-12T16:39:47.727 回答