Cha*_*e K 12 database database-design polymorphic-associations
在类似的应用程序,以计算器,我建设,我想决定什么关系我的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
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哲学倾向于将数据模型的实施放入应用程序层.但是,如果没有约束强制数据库中的完整性,您就有可能存在应用程序中的错误或查询工具的即席查询会损害数据完整性的风险.