如何让 jOOQ 生成不引用主键的复合外键?

Posted

技术标签:

【中文标题】如何让 jOOQ 生成不引用主键的复合外键?【英文标题】:How to make jOOQ generate composite foreign keys not referencing a primary key? 【发布时间】:2017-08-05 12:03:36 【问题描述】:

使用带有 H2 1.4.194 的最新 jOOQ,不会为以下(简化)架构生成 Keys.java 中的外键:

CREATE TABLE t (a INT, b INT, PRIMARY KEY (a));
CREATE TABLE u (a INT, b INT, FOREIGN KEY (a,b) REFERENCES t (a,b));

如下添加唯一约束无济于事:

CREATE TABLE t (a INT, b INT, PRIMARY KEY (a), UNIQUE (a,b));
CREATE TABLE u (a INT, b INT, FOREIGN KEY (a,b) REFERENCES t (a,b));

更改 FK 以引用主键(无论是简单的还是复合的)使 FK 出现。

通过 H2 查询 FK 可以正常工作。

看起来不像是回归(尝试了各种 3.x jOOQ),所以想知道我是否做错了什么。生成器配置(通过 maven 插件)如下:

<name>org.jooq.util.JavaGenerator</name>
<database>
    <name>org.jooq.util.h2.H2Database</name>
    <includes>.*</includes>
    <excludes />
    <inputSchema>PUBLIC</inputSchema>
</database>

【问题讨论】:

t(a, b) 上是否有唯一约束或索引?它应该与约束一起使用,但可能不适用于索引 在我的非简化示例中,我实际上有一个独特的约束 - 没有帮助。有趣的是,约束本身生成为createUniqueKey(T.T, "X", T.T.A);——应该是createUniqueKey(T.T, "X", T.T.A, T.T.B);,对吧?同样,这在 INFORMATION_SCHEMA 中是正确的。 感谢您提供详细信息。也许,为了完整起见,您可以用确切的唯一约束更新您的问题吗?我认为这是一个错误。很快就会调查,然后给你一个答案。 嗯,有趣的更新。请问:你的主键不包含b是什么原因? 很好,是的,我能做到。我的一些表只关心用户,而不关心组织 - 在这些情况下,我的 FK 引用只是 (id),而不是 (id, type)。我误解了级联删除引用非 PK 是不允许的。但是,这显然是错误的,所以我得救了! 【参考方案1】:

解决缺少的外键

从 jOOQ 3.14 开始,如果由于 jOOQ 的限制,或者因为您的架构中实际上没有任何外键,或者因为您正在生成视图,您在生成的输出中缺少外键,您可以创建synthetic objects,包括synthetic primary keys、synthetic unique keys,并从synthetic foreign keys引用它们,配置如下:

<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <foreignKeys>
          <foreignKey>
            <tables>U</tables>
            <fields>
              <field>A</field>
              <field>B</field>
            </fields>
            <referencedTable>T</referencedTable>
            <referencedFields>
              <field>A</field>
              <field>B</field>
            </referencedFields>
          </foreignKey>
        </foreignKeys>
      </syntheticObjects>
    </database>
  </generator>
</configuration>

有不同的方法来配置它,例如通过名称引用或列引用等check out the manual for details。

历史答案(这是一个错误)

jOOQ 的代码生成器在内部运行的查询是这样的:

select 
  "CROSS_REFERENCES"."FK_NAME", 
  "CROSS_REFERENCES"."FKTABLE_NAME", 
  "CROSS_REFERENCES"."FKTABLE_SCHEMA", 
  "CROSS_REFERENCES"."FKCOLUMN_NAME", 
  "CONSTRAINTS"."CONSTRAINT_NAME", 
  "CONSTRAINTS"."CONSTRAINT_SCHEMA"
from "INFORMATION_SCHEMA"."CROSS_REFERENCES"
  join "INFORMATION_SCHEMA"."CONSTRAINTS"
  on (
    "CROSS_REFERENCES"."PK_NAME" = "CONSTRAINTS"."UNIQUE_INDEX_NAME"
    and "CROSS_REFERENCES"."PKTABLE_NAME" = "CONSTRAINTS"."TABLE_NAME"
    and "CROSS_REFERENCES"."PKTABLE_SCHEMA" = "CONSTRAINTS"."TABLE_SCHEMA"
  )
where (
  "CROSS_REFERENCES"."FKTABLE_SCHEMA" in (
    'PUBLIC'
  )
  and "CONSTRAINTS"."CONSTRAINT_TYPE" in (
    'PRIMARY KEY', 'UNIQUE'
  )
)
order by 
  "CROSS_REFERENCES"."FKTABLE_SCHEMA" asc, 
  "CROSS_REFERENCES"."FK_NAME" asc, 
  "CROSS_REFERENCES"."ORDINAL_POSITION" asc

查询看起来是正确的,但似乎对 H2 如何在这些字典视图中编码唯一约束存在误解。或者 H2 中的错误。

我创建了两个问题,让我们看看哪个是正确的:

H2 中的错误:https://github.com/h2database/h2database/issues/466 jOOQ 中的错误:https://github.com/jOOQ/jOOQ/issues/5972

【讨论】:

以上是关于如何让 jOOQ 生成不引用主键的复合外键?的主要内容,如果未能解决你的问题,请参考以下文章

替换其他表中作为外键的主键

在复合键和外键之间创建关系

JPA @EmbeddedId 未生成序列

MyBatis-Generator生成复合主键的表模型类

如何在实体框架中为复合主键的特定列创建外键

mysql复合外键引用超过2个属性