JPA中使用联合主键产生的若干问题

最近在做一个项目,关于考试系统的,后台用的SpringBoot框架,因为设计需求,需要在某个实体中使用一个联合主键,而同时这个实体由与其他两个实体有映射关系,于是开始了踩坑之旅。。。

先看一下实体,是一个考试的实体,联合主键是学生的id和试卷的id,同时一个学生可以有多场考试,一张试卷也可以用在多场考试中,所以还有两个一对多的关系映射。

//联合主键
@Embeddable
public class StudentPaperPk implements Serializable{

    private int studentId;

    private int paperId;
}


@Entity
public class Exam {

    @EmbeddedId
    private StudentPaperPk pk;

    @Column(nullable = false,length = 255)
    private String name;

    @Column
    private int timeSec;

    @Column
    private String result;

    @Column
    private Date date;

    @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.PERSIST,CascadeType.MERGE})
    @JoinColumn(name = "student")
    private Student student;

    @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.PERSIST,CascadeType.MERGE})
    @JoinColumn(name = "paper")
    private Paper paper;
}

@Entity
public class Student {
    @Id
    @GeneratedValue
    private int id;
    @Column(nullable = false,unique = true)
    private String number;
    @Column(nullable = false,length = 50)
    private String name;
    @Column(nullable = false,length = 50)
    private String className;

    @OneToMany(mappedBy = "student",fetch = FetchType.EAGER)
    private Set<Exam> examSet;
}

@Entity
public class Paper {
    @Id
    @GeneratedValue
    private int id;
    @Column(nullable = false,length = 50)
    private String paperName;
    @Column
    private String questions;

    @ManyToMany(fetch = FetchType.EAGER,cascade = {CascadeType.PERSIST,CascadeType.MERGE})
    @JoinTable(name = "Paper_Question",
            joinColumns = {@JoinColumn(name = "paperId",referencedColumnName = "id")},
            inverseJoinColumns ={@JoinColumn(name = "questionId",referencedColumnName = "id")}
    )
    private Set<Question> questionSet;

    @OneToMany(mappedBy = "paper",fetch = FetchType.EAGER)
    private Set<Exam> examSet;
}

坑1:联合主键长度不超过1000byte

        一开始使用的是学号和试卷号作为联合主键,而且这两者都是字符串,但是不管长度定多少,都会报长度超过1000byte的错误,所以我猜测是JPA联合主键不支持字符串。

坑2:注解位置

       大家都清楚联合主键有三种注解方式,一开始我是将@EmbeddedId注解在pk的getter方法上,测试没问题,可以正常建表,但是当我加上一对多映射之后,会报下面这种错误:

org.hibernate.MappingException: Could not determine type for: com.model.Paper, at table: exam, for columns: [org.hibernate.mapping.Column(paper)]


       原来注解位置要一致才能参照得到。

坑3:JPARepository的使用

       大家都知道JPA提供了很方便的使用方式,只要定义一个接口继承JpaRepository,然后就可以用findByXXX来实现简单的查询了,对于联合主键的实体,有两个地方要注意:

1.   JapRepository的实例化类型,第一个写实体类,第二个要写联合主键类,而不是Long。

2.   find方法要写成findBy+实体类中的联合主键属性名+联合主键类中的属性名,如

public interface ExamRepository extends JpaRepository<Exam,StudentPaperPk> {
    List<Exam> findByPkStudentId(int studentId);
}

在JPA中使用联合主键的上辈子都是折翼的天使!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值