如何解决三向多态关联?

STE*_*ter 5 mysql normalization polymorphic-associations

首先让我说我使用的是MySQL(不是事务性的),并且无法更改.此外,为简洁明了,我在这里简化了表格.

在这个例子中,'Lesson'由它的内部属性和一个外部属性组成,它有自己的属性'Readings'.'Readings'拥有自己的密钥依赖属性和三个不同的外部属性(阅读源).

我想避免在这里产生的多态关联,但我无法绕过它.在此示例中,'Reading'表中的'sourceId'将包含三个表"ExternalURL","InternalURL"和"Book"之一的id.此外,字段"polytable"将包含上述"id"来自的表名.

有人可以花一点时间来解释如何解决这种维护RI的问题,还是为了效率而应该留下它?

感谢您的时间和考虑,

蒂姆

                       -------------
                      | ExternalURL |
                       -------------
                      | id          |
                      | badlink     |
                      | url         |
                      |             |
                      |             |
                       -------------
                            |
                            |
                            |
                           / \
 ------------          -------------          -------------
| Lesson     |-------<| Reading     |>-------| InternalURL |
 ------------          -------------          -------------
| id         |        | id          |        | id          |
| label      |        | lessonId    |        | url         |
| summary    |        | sourceId    |        |             |
| lessonOrder|        | polytable   |        |             |
| active     |        | label       |        |             |
 ------------          -------------          -------------
                            \ /
                             |
                             |
                       ------------  
                      | Book       |
                       ------------ 
                      | id         |
                      | label      |
                      | summary    |
                      | lessonOrder|
                      | active     |
                       ------------ 
Run Code Online (Sandbox Code Playgroud)

Bil*_*win 7

您至少有两个选项可以保留RI:

  1. 添加几个可空的FK列Reading,每个读取类型一个.其中只有一个应该是非null.

    CREATE TABLE Reading (
      id INT AUTO_INCREMENT PRIMARY KEY,
      lessonId INT NOT NULL,
      bookId INT NULL,
      externalUrlId INT NULL,
      internalUrlId INT NULL,
      FOREIGN KEY (bookId) REFERENCES Book(id),
      FOREIGN KEY (externalUrlId) REFERENCES ExternalUrl(id),
      FOREIGN KEY (internalUrlId) REFERENCES InternalUrl(id)
    );
    
    Run Code Online (Sandbox Code Playgroud)

    强制执行其中一个外键列是非空的是触发器的任务,否则您必须在应用程序代码中执行此操作.但至少你可以定义外键.

  2. 添加一个supertable Readable,它是每个其他特定可读类型的父级.

    CREATE TABLE Readable (
      id INT AUTO_INCREMENT PRIMARY KEY,
      readable_type CHAR(1) NOT NULL,
      UNIQUE KEY (id, readable_type)
    );
    
    CREATE TABLE Book (
      id INT PRIMARY KEY, -- not AUTO_INCREMENT
      readable_type CHAR(1) NOT NULL, -- must be 'B'
      FOREIGN KEY (id, readable_type) REFERENCES Readable(id, readable_type)
    );
    
    ... similar tables for ExternalUrl and InternalUrl...
    
    Run Code Online (Sandbox Code Playgroud)

    然后让阅读也参考Readable.

    CREATE TABLE Reading (
      id INT AUTO_INCREMENT PRIMARY KEY,
      lessonId INT NOT NULL,
      sourceId INT NOT NULL,
      FOREIGN KEY (sourceId) REFERENCES Readable(id)
    );
    
    Run Code Online (Sandbox Code Playgroud)

    我在答案中更详细地描述了这个解决方案为什么你不能在多态关联中拥有外键?.