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

Cha*_*e K 12 database database-design polymorphic-associations

在类似的应用程序,以计算器,我建设,我想决定什么关系我的Questions,AnswersComments表应该有.

我可以拥有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
Run Code Online (Sandbox Code Playgroud)
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
  );
Run Code Online (Sandbox Code Playgroud)

Bil*_*win 16

我会选择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;
Run Code Online (Sandbox Code Playgroud)

这称为类表继承.本文概述了使用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; 
Run Code Online (Sandbox Code Playgroud)

您可以在此示例中使用外键约束,我建议您这样做!:-)

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