在使用InheritanceType.join的JPA实体层次结构中,与子类的所有关系都会导致超类表上的外键约束
我有以下JPA2.0实体在使用InheritanceType.join的JPA实体层次结构中,与子类的所有关系都会导致超类表上的外键约束,jpa,foreign-keys,eclipselink,joined-subclass,db-schema,Jpa,Foreign Keys,Eclipselink,Joined Subclass,Db Schema,我有以下JPA2.0实体 @Entity @Inheritance(strategy= InheritanceType.JOINED) public abstract class BookKeepingParent implements Serializable { @Id protected Long Id; ... } @Entity public class Employee extends BookKeepingParent { private Stri
@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;
...
}
我想让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)
)
前两个表相同,但它通过以下方式生成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)
)
您可以注意到,fk\u employee\u role\u id
引用的是bookkeepingparent
表,而不是role
表。我有一个很大的JPA实体继承权,我希望bookkeepingparent是其中大多数实体的超类。这主要是因为一些非常具体的Id生成策略和其他记账活动。这种设计有助于将所有这些簿记代码与函数代码分开,并让编写函数代码的程序员不必担心它
所有这些都正常工作,直到表格数量增加。现在我们看到,对于所有ManyToOne
和OneToOne
关系,JPA正在生成引用父表的外键。对于200多个表,插入速度已经很慢,因为所有外键约束都引用bookekeepingparent,并且第一次持久化时,每个实体都会插入到簿记父表中。我猜是在检查150多个约束条件
所以,以下是我的问题:JPA为什么要这么做?这是JPA的标准行为吗?(我正在使用EclipseLink)如果我手动更改DB模式,他们会遇到什么陷阱吗
这是我关于StackOverflow的第一个问题,我尽了最大努力寻找任何现有的答案。如果我错过了,我道歉。谢谢 您使用的是联合继承,这意味着对于每个类,bookkeepingparenttable是主表,任何子类表都是次表。子类的主键是从父类继承的,外键必须引用id,因此所有子类都将通过设计引用bookkeepingparenttable中的id。不同的提供者允许引用非pk字段,但这可能会导致问题,因为解析引用可能需要数据库命中,而不是使用缓存
数据库约束与JPA无关,因此您可以根据需要更改它们,只要插入更新和删除仍然符合要求,就不会影响应用程序。比方说,JPA需要缓存来执行EntityManager.find()之类的操作。由于超类和子类的ID是相同的,所以使用哪个ID作为缓存的“键”并不重要。另外,关于DB约束,EclipseLink正在创建的约束有点“不准确”——使用外键引用超类允许在Employee的Role列中添加Role以外的表ID。因此,我的插入和更新肯定会符合约束条件,因为我的插入和更新比EclipseLink提出的要窄。所以我还是不明白他们为什么这么做。无论如何,谢谢。如前所述,主表是bookkeepingparent,因此默认值将始终指向EclipseLink中的该表。您可以通过在映射上定义joincolumn以转到辅助表来更改它,这将更改为DDL创建的约束-但它可能会有不命中缓存的限制。因此,更改DDL脚本可能比更改映射更好。如果我更改DDL脚本,使FK引用子类表,我将收到约束冲突错误。所以这不是一个解决方案。在我看来,这似乎是EclipseLink中的一个bug,因为它不能准确地表示对象关系。JPA指定子对象使用父对象的主键,并且引用必须始终指向主键,因此它根据规范工作。也就是说,它偶尔会出现,如图所示。children表也有一个主键。所以它可以很容易地被外键引用。我同意你的观点,FK应该引用子类。这似乎是EclipseLink中的一个bug,因为这样的映射显然是错误的,不能正确地反映关系。