如何解决三向多态关联?

时间:2013-03-05 00:09:43

标签: 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     |
                       ------------ 

1 个答案:

答案 0 :(得分:7)

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

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

    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)
    );
    

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

  2. 添加一个超级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...
    

    然后让Reading也引用Readable。

    CREATE TABLE Reading (
      id INT AUTO_INCREMENT PRIMARY KEY,
      lessonId INT NOT NULL,
      sourceId INT NOT NULL,
      FOREIGN KEY (sourceId) REFERENCES Readable(id)
    );
    

    我在对Why can you not have a foreign key in a polymorphic association?的回答中更详细地描述了这个解决方案。

相关问题