JPA 派生的复合键

Posted

技术标签:

【中文标题】JPA 派生的复合键【英文标题】:JPA derived composite key 【发布时间】:2014-09-04 19:36:04 【问题描述】:

我正在学习 JPA 2.1。我使用 sql 设计了一个数据库,但无法使用 JPA 2.1 做同样的事情。我列出了 sql 脚本。

create table SchoolClass (classNo int, constraint schoolClassPK Primary Key (classNo));
create table Section (classNo int, sectionId varchar(4), constraint sectionPK Primary Key(classNo, sectionId), constraint sectionClassNoFK Foreign Key (classNo) References SchoolClass(classNo));
create table Student (classNo int, sectionId varchar(4), rollNo int, name varchar(30), constraint studentPK Primary Key (classNo, sectionId, rollNo), constraint studentClassNoFK Foreign Key (classNo, sectionId) References Section(classNo, sectionId));

我的问题是在实现学生课程。这是我尝试用 JPA 做的事情:

@Entity
public class Schoolclass implements Serializable 

@Id
private int classNo;

//other members follow




// IdClass
public class SectionCK implements Serializable 

private int classNo;
private String sectionId;

// hashCode(), equals(Object), other members follow




@Entity
@IdClass(SectionCK.class)
public class Section implements Serializable 

@Id
private int sectionPK;

@Id
private String sectionId;

@Id
@ManyToOne(cascade =  PERSIST, MERGE )
@JoinColumn(name="SchoolClass_ClassNo", referencedColumnName="classNo")
private SchoolClass classNo;

//other members follow




// IdClass
public class StudentCK implements Serializable 

private int classNo;
private String sectionId;
private int rollNo;

// hashCode(), equals(Object), other members follow




@Entity
@IdClass(StudentCK.class)
public class Student implements Serializable 

@Id
private int rollNo;

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

@Id
@ManyToOne(cascade =  PERSIST, MERGE )
@JoinColumns(
@JoinColumn(name="Section_SectionId", referencedColumnName="sectionId"),
@JoinColumn(name="Section_ClassNo", referencedColumnName="classNo")
)
private Section sectionId;

//other members follow

但这无法生成上述数据库。需要进行哪些更改?

【问题讨论】:

我是否在您的 SQL 代码中遗漏了什么?对于表Section,您无需定义classSection 列,而是在PK 中引用它。与表相同StudentclassSection 在哪里?在Student 中,您将classNoSection 引用为FK。这样的列只存在于SchoolClass classNo 没问题。只有classSection坚持 您能详细说明失败的原因吗? zbigniewTomczak 的答案似乎是正确的,所以如果它不起作用,请显示什么错误或它产生了什么。您在上面的示例中加入列似乎是错误的,因为 Section 表中没有“SchoolClass_ClassNo”字段 - 如果这是使用的外键字段,它应该是“classNo”。在 Student 映射中定义的 joincolumns 存在相同的问题 - 它们与学生表中所需的字段不匹配。 @zbigniewTomczak 感谢您指出 SQL 脚本的问题,我已纠正。 【参考方案1】:

无论如何,请尝试从以下代码开始,然后朝着所需的映射方向努力。请记住,@IdClass 中字段的名称、类型和数量必须与实体中标记为 @Id 的字段匹配。

public class SectionCK 
    private String sectionId;
    private int schoolClass;


@Entity
@IdClass(SectionCK.class)
public class Section implements Serializable 
    @Id
    private String sectionId;

    @Id
    @ManyToOne
    @JoinColumn(name="classNo")
    private SchoolClass schoolClass;


public class StudentCK implements Serializable 
    private int rollNo;
    private SectionCK section;


@Entity
@IdClass(StudentCK.class)
public class Student implements Serializable 
    @Id
    private int rollNo;

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

    @Id
    @ManyToOne
    @JoinColumns(
    @JoinColumn(name="sectionId", referencedColumnName="sectionId"),
    @JoinColumn(name="classNo", referencedColumnName="classNo")
    )
    private Section section;


此代码生成以下表格:

Table: Student
COLUMN_NAME         |TYPE_NAME
------------------------------
ROLLNO              |INTEGER  
NAME                |VARCHAR  
CLASSNO             |INTEGER 
SECTIONID           |VARCHAR  

Table: SchoolClass
COLUMN_NAME         |TYPE_NAME
------------------------------
CLASSNO             |INTEGER 

Table: Section
COLUMN_NAME         |TYPE_NAME
------------------------------
SECTIONID           |VARCHAR  
CLASSNO             |INTEGER  

【讨论】:

我的代码和你的代码也没有区别。这是我已经尝试过但不起作用的方法。 是的,有区别。 1. 请注意,我在StudentCK 中使用SectionCK。 2. 您将有@JoinColumn name 属性产生不正确的列名。我的没问题。 3. 您还混合了@Id 名称和@IdClass 字段名称(sectionPK)之间的名称。 zbigniewTomczak 感谢您指出问题并给出解决方案。

以上是关于JPA 派生的复合键的主要内容,如果未能解决你的问题,请参考以下文章

JPA/Hibernate 和复合键

具有复合键的 JPA ManyToOne

使用 Quarkus 的 JPA 中的复合主键是不是可能?

jpa 多对多,带有附加列和复合键

在 JPA 中使用继承时的复合外键问题

Spring data JPA只有一个复合键自动递增