【问题标题】:Hibernate/JPA: using partial composite primary key from parent as both foreign key and primary key in childHibernate/JPA:使用来自父级的部分复合主键作为外键和子级的主键
【发布时间】:2020-03-01 16:24:04
【问题描述】:

我有 2 个实体类:学生是父类,地址是子类,具有一对一映射:

学生

student_id int (pk), roll_no int (pk), 名称 varchar

地址

student_id (pk, fk), 国家变量

地址实体中的student_id既是主键也是外键

学生实体班:

@Entity
@Table(name = "student")
public class Student {

    @EmbeddedId
    private StudentPrimaryKey studentPrimaryKey;

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

    @OneToOne(mappedBy = "student", cascade = CascadeType.ALL)
    private Address address;
    ........

StudentPrimaryKey 类:

@Embeddable
public class StudentPrimaryKey implements Serializable{

    @Column(name = "student_id")
    private long id;

    @Column(name = "roll_no")
    private long rollNo;
    ....

地址实体类:

@Entity
@Table(name = "address")
public class Address {

    @Id
    @Column(name  = "student_id")
    private long id;

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

    @OneToOne
    @JoinColumn(name = "student_id")
    @MapsId
    private Student student;
    .......

例外是 - org.hibernate.AnnotationException:@MapsId 映射中的隐式列引用失败,尝试使用显式referenceColumnNames

我知道父表中有 2 个主键列,@MapsId 无法确定应该将外键映射到父表中的哪一个,所以我尝试在地址实体中使用 referencedColumnName -

@OneToOne
    @JoinColumn(name = "student_id", referencedColumnName = "student_id")
    @MapsId
    private Student student; 

新例外: 在@MapsId 映射中找不到列引用:roll_no

从上面,它试图从父类的复合主键中找到缺失的列,但我们不需要这个列。

[Hibernate - Composite Primary Key contains Foreign Key

这是共享相同问题的链接之一,即 JPA/hibernate 不允许部分复合主键成为外键。

请提供您的支持以帮助我处理此问题。

【问题讨论】:

    标签: hibernate jpa


    【解决方案1】:

    如果Student 只能通过其idrollNo 的组合来唯一标识,则相应的Address 也需要其主键/外键中的两个字段,并且应该如下所示(注意它使用相同的@EmbeddedIdStudentPrimaryKey):

    @Entity
    @Table(name = "address")
    public class Address {
    
        @EmbeddedId
        private StudentPrimaryKey primaryKey;
    
        @MapsId
        @JoinColumns({
            @JoinColumn(name="student_id", referencedColumnName="student_id"),
            @JoinColumn(name="roll_no", referencedColumnName="roll_no") })
        @OneToOne
        Student student;
    
        @Column(name  = "country")
        private String country;
    
        ...
    

    您还需要将roll_no 列添加到address 表中。

    如果 Student 可以通过其 id 唯一标识(正如您的 Address 映射所暗示的那样),那么您可以从主键中删除 rollNo 并在 @ 上使用简单的 @Id 映射987654335@ 和 @Basic 映射到 rollNo

    【讨论】:

    • 这意味着即使学生类的 'id' 列在数据库中具有唯一性属性,hibernate 也无法支持我的用例(此列的值不会重复)?
    • @Kiran 如果id 列确实是唯一的,您应该能够使用简单的@Id 注释(而不是当前的@EmbeddedId)。在保存到数据库之前,您只需要确保rollNo 不是null(这样就不会违反数据库的主键约束)。你试过吗?
    • 这行得通,但我不认为它是设计实体类的理想方式。数据库表和实体类需要相互对齐。
    • @Kiran 不一定。 @Id 注释字段只需要唯一标识一个实体。不要求它对应于 DDL 定义的实体表的主键。您可以使用表中保证非空且唯一的任何列(或列集)。
    猜你喜欢
    • 2018-01-13
    • 2020-02-19
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-15
    • 1970-01-01
    • 2017-01-30
    相关资源
    最近更新 更多