InheritanceType.JOINED、@PrimaryKeyJoinColumn 和嵌套子类

smi*_*tan 1 java hibernate jpa

我正在开始使用 Hibernate,有一个关于 InheritanceType.JOINED 和 @PrimaryKeyJoinColumn 的问题。

给定以下数据库表,其中员工引用人员,经理引用员工:

create table person (person_id int(10) auto_increment, 
                     name varchar(100),
                     primary key (person_id));

create table employee (employee_id int(10) auto_increment,
                       person_id int(10),
                       salary int(10),
                       primary key (employee_id));

create table manager (manager_id int(10) auto_increment,
                      employee_id int(10),
                      shares int(10),
                      primary key (manager_id));
Run Code Online (Sandbox Code Playgroud)

我可以为 Person 和 Employee 创建前两个类,如下所示:

@Entity
@Table(name="person")
@Inheritance(strategy=InheritanceType.JOINED)
public class Person {

    @Id
    @GeneratedValue
    @Column(name="person_id")
    private int personId;

    @Column(name="name")
    private String name;
}


@Entity
@Table(name="employee")
@PrimaryKeyJoinColumn(name="person_id")
public class Employee extends Person {

    @GeneratedValue
    @Column(name="employee_id")
    private int employeeId;

    @Column(name="salary")
    private int salary;
}
Run Code Online (Sandbox Code Playgroud)

当谈到 Manager 类时,我不确定 @PrimaryKeyJoinColumn 使用哪个值。通过阅读 JPA 规范,我应该在整个超类/子类/子类层次结构中仅使用一个 id,我怀疑应该是 person_id。

我应该从经理表中删除employee_id列并将其替换为person_id吗?我问的原因是,在数据库中拥有“级联”主键似乎很自然(即经理不直接引用人员),但我相信 Hibernate 要求所有子子类(无论“深”)都包含一个外键返回到超类。对我的断言进行一些确认将非常有用。

bit*_*kot 5

您可以使用任何您想要的列名称。 @PrimaryKeyJoinColumn注释用于告诉hibernate连接表中外键列的名称是什么。

@Entity
@Table(name = "manager")
@PrimaryKeyJoinColumn(name = "employee_id")
public class Manager extends Employee{
    private String branch;
}
Run Code Online (Sandbox Code Playgroud)

此代码意味着在manager表中您有一个名为的列employee_id,它是表的外键employee

此注释是可选的,因此如果您不提供它,那么外键列名称将与基类中的键名称相同(如果多级继承则为超级基),在您的情况下,如果您不提供,则任何子类都会作为person_id外键。

employee_id如果您想保留表中的字段名称,manager那么您必须像这样提供。

@PrimaryKeyJoinColumn(name="employee_id")

如果您根本不提供此注释,那么将会有一个列名person_id用作employee表的外键。

这是文档所说的。

此注释指定一个主键列,该主键列用作连接到另一个表的外键。

用于将JOINED映射策略中实体子类的主表连接到其超类的主表;它在SecondaryTable注释中使用,将辅助表连接到主表;它可以用在 OneToOne 映射中,其中引用实体的主键用作被引用实体的外键。

如果在 JOINED 映射策略中没有为子类指定 PrimaryKeyJoinColumn 注解,则假定外键列与超类主表的主键列同名

编辑

当我尝试通过 id 检索管理器时,Hibernate 正在执行查询。

select
            manager0_.id as id1_4_0_,
            manager0_2_.name as name2_4_0_,
            manager0_1_.employee_id as employee1_1_0_,
            manager0_1_.salary as salary2_1_0_,
            manager0_.branch as branch1_2_0_ 
        from
            manager manager0_ 
        inner join
            employee manager0_1_ 
                on manager0_.id=manager0_1_.id 
        inner join
            person manager0_2_ 
                on manager0_.id=manager0_2_.id 
        where
            manager0_.id=?
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,经理有员工的外键,而不是人员表。我还没有创建表。我用的是hbm2ddl=create.

这意味着 Hibernate 本身使用级联主键而不是仅使用超级父键创建表。

我理解您的困惑,即使我在 hibernate文档中找不到任何内容。它只是说 FK 将指向超类主键。它不指定直接超类或顶级超类。虽然我检查了其他 JPA 实现,即OpenJPA。它确实明确指出 FK 指向直接超类。