简体   繁体   English

MySQL - 条件外键约束

[英]MySQL - Conditional Foreign Key Constraints

I have following comments table in my app:我的应用程序中有以下comments表:

comments
--------
id           INT
foreign_id   INT
model        TEXT
comment_text TEXT
...

the idea of this table is to store comments for various parts of my app - it can store comments for blog post ie:这个表的想法是存储我应用程序各个部分的评论 - 它可以存储博客文章的评论,即:

1|34|blogpost|lorem ipsum...

user picture:用户图片:

2|12|picture|lorem ipsum...

and so on.等等。

now, is there a way to force FOREIGN KEY constraint on such data?现在,有没有办法强制对此类数据进行 FOREIGN KEY 约束?

ie something like this in comments table:即评论表中的类似内容:

FOREIGN KEY (`foreign_id`) REFERENCES blogposts (`id`)
-- but only when model='blogpost'

You're attempting to do a design that is called Polymorphic Associations .您正在尝试进行称为Polymorphic Associations的设计。 That is, the foreign key may reference rows in any of several related tables.也就是说,外键可以引用几个相关表中的任何一个中的行。

But a foreign key constraint must reference exactly one table.但是外键约束必须正好引用一个表。 You can't declare a foreign key that references different tables depending on the value in another column of your Comments table.您不能根据Comments表的另一列中的值声明引用不同表的外键。 This would violate several rules of relational database design.这将违反关系数据库设计的几条规则。

A better solution is to make a sort of "supertable" that is referenced by the comments.更好的解决方案是制作一种由注释引用的“超级表”。

CREATE TABLE Commentable (
  id SERIAL PRIMARY KEY
);

CREATE TABLE Comments (
  comment_id SERIAL PRIMARY KEY,
  foreign_id INT NOT NULL,
  ...
  FOREIGN KEY (foreign_id) REFERENCES Commentable(id)
);

Each of your content types would be considered a subtype of this supertable.您的每个内容类型都将被视为此超级表的子类型。 This is analogous to the object-oriented concept of an interface .这类似于面向对象的接口概念。

CREATE TABLE BlogPosts (
  blogpost_id INT PRIMARY KEY, -- notice this is not auto-generated
  ...
  FOREIGN KEY (blogpost_id) REFERENCES Commentable(id)
);

CREATE TABLE UserPictures (
  userpicture_id INT PRIMARY KEY, -- notice this is not auto-generated
  ...
  FOREIGN KEY (userpicture_id) REFERENCES Commentable(id)
);

Before you can insert a row into BlogPosts or UserPictures , you must insert a new row to Commentable to generate a new pseudokey id.在向BlogPostsUserPictures插入一行之前,您必须向Commentable插入一个新行以生成新的伪键 ID。 Then you can use that generated id as you insert the content to the respective subtype table.然后,您可以在将内容插入到相应的子类型表时使用生成的 id。

Once you do all that, you can rely on referential integrity constraints.完成所有这些操作后,您就可以依赖参照完整性约束了。

In MySQL 5.7 you can have a single polymorphic table AND enjoy something like a polymorphic foreign key!在 MySQL 5.7 中,您可以拥有一个多态表并享受多态外键之类的东西!

The caveat is that technically you will need to implement it as multiple FKs on multiple columns (one per each entity that has comments), but the implementation can be limited to the DB side (ie you will not need to worry about these columns in your code).需要注意的是,从技术上讲,您需要将它实现为多个列上的多个 FK(每个具有评论的实体一个),但实现可以仅限于 DB 端(即您不需要担心这些列在您的代码)。

The idea is to use MySQL's Generated Columns:这个想法是使用 MySQL 的 Generated Columns:

CREATE TABLE comments (
  id INT NOT NULL AUTO_INCREMENT,
  foreign_id INT,
  model TEXT,
  commented_text TEXT,
  generated_blogpost_id INT AS (IF(model = 'blogpost', foreign_id, NULL)) STORED,
  generated_picture_id INT AS (IF(model = 'picture', foreign_id, NULL)) STORED,
  PRIMARY KEY (id) ,
  FOREIGN KEY (`generated_blogpost_id`) REFERENCES blogpost(id) ON DELETE CASCADE,
  FOREIGN KEY (`generated_picture_id`) REFERENCES picture(id) ON DELETE CASCADE
)

You can ignore the generated_* columns;您可以忽略generated_* _ generated_*列; they will be populated automatically by MySQL as comments are added or modified, and the FKs defined for them will ensure data consistency as expected.它们将在添加或修改注释时由 MySQL 自动填充,并且为它们定义的 FK 将确保数据的一致性。

Obviously it would impact both the size requirements and performance, but for some (most?) systems it would be negligible, and a price worth paying for achieving data consistency with a simpler design.显然,它会影响大小要求和性能,但对于某些(大多数?)系统来说,它可以忽略不计,并且为通过更简单的设计实现数据一致性而付出的代价是值得的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM