在使用 InheritanceType.JOINED 的 JPA 实体层次结构中,与子类的所有关系都会导致超类表上的外键约束

Nik*_*esh 5 jpa foreign-keys eclipselink db-schema joined-subclass

我有以下 JPA 2.0 实体

@Entity
@Inheritance(strategy= InheritanceType.JOINED)
public abstract class BookKeepingParent implements Serializable {
    @Id
    protected Long Id;
    ...
}

@Entity
public class Employee extends BookKeepingParent {
    private String name;

    @ManyToOne
    private Role role;
    ...
}

@Entity
public class Role extends BookKeepingParent {
    private String name;
    ...
}
Run Code Online (Sandbox Code Playgroud)

我想让 JPA 为我生成表,因为它可以更轻松地在多个位置安装。我通常会期望它产生这个:

CREATE TABLE bookkeepingparent (
  id bigint NOT NULL,
  dtype character varying(31),
  CONSTRAINT bookkeepingparent_pkey PRIMARY KEY (id )
)

CREATE TABLE role (
  id bigint NOT NULL,
  name character varying(255),
  CONSTRAINT role_pkey PRIMARY KEY (id ),
  CONSTRAINT fk_role_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id)
)

CREATE TABLE employee (
  id bigint NOT NULL,
  name character varying(255),
  role_id bigint,
  CONSTRAINT employee_pkey PRIMARY KEY (id ),
  CONSTRAINT fk_employee_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id),
  CONSTRAINT fk_employee_role_id FOREIGN KEY (role_id) REFERENCES role (id)
)
Run Code Online (Sandbox Code Playgroud)

前两个表相同,但它以employee这种方式生成表:

CREATE TABLE employee (
  id bigint NOT NULL,
  name character varying(255),
  role_id bigint,
  CONSTRAINT employee_pkey PRIMARY KEY (id ),
  CONSTRAINT fk_employee_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id),
  CONSTRAINT fk_employee_role_id FOREIGN KEY (role_id) REFERENCES bookkeepingparent (id)
)
Run Code Online (Sandbox Code Playgroud)

您可以注意到fk_employee_role_id引用的是bookkeepingparent表,而不是role表。我有一个很大的 JPA 实体层次结构,我希望 bookkeepingparent 成为其中大多数实体的超类。这主要是因为一些非常具体的 Id 生成策略和其他簿记活动。这种设计有助于保持本书的所有代码与功能代码分开,让程序员在处理功能代码时不必担心。

所有这些工作正常,直到表的数量增加。现在我们看到,对于所有ManyToOneOneToOne关系,JPA 正在生成引用父表的外键。对于 200 个奇数表,插入已经很慢,因为所有外键约束都引用了簿记父表,并且每个实体在第一次持久化时都会插入到簿记父表中。我猜这是检查大约 150 个奇怪的约束。

所以,以下是我的问题:JPA 为什么要这样做?这是标准的 JPA 行为吗?(我正在使用 EclipseLink)如果我手动更改数据库架构,他们是否会遇到任何陷阱?

这是我在 StackOverflow 上的第一个问题,我尽力搜索任何现有的答案。如有遗漏,请见谅。谢谢。

Chr*_*ris 1

您正在使用联合继承,这意味着对于每个类,bookkeepingparenttable 是主表,任何子类表都是辅助表。子类的主键是从父类继承的,外键必须引用id,所以在设计上它们都会引用bookkeepingParentTable中的id。不同的提供程序允许引用非 pk 字段,但这可能会导致问题,因为解析引用可能需要数据库命中而不是使用缓存。

数据库约束与 JPA 无关,因此您可以根据需要更改它们,只要插入、更新和删除仍然符合要求,就不会影响应用程序。