欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Data JPA设置表联合主键

程序员文章站 2022-04-25 07:57:08
...

遇到了一个新的问题,就是如何使用 Spring Data JPA 建立表的联合主键?网上找了很多答案,自己也踩了一些坑,总结出了三种方式,记录一下。

第一种方式:

第一种方式是直接使用 @Id 这个注解,来设置联合主键,例如下面这样,我要在 stu_no 和 stu_name 上建立联合主键:

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

    @Id
    @Column(name = "stu_no", nullable = false, length = 11)
    private Integer stuNo;

    @Id
    @Column(name = "stu_name", nullable = false, length = 128)
    private String stuName;

    @Column(name = "stu_age", nullable = false, length = 3)
    private Integer stuAge;

    @Column(name = "class_id", nullable = false, length = 8)
    private String classId;
}

这种方式很简单,但是问题也是存在的。例如我想把 stu_no 设置为自动递增,加上 @GeneratedValue ,就是不生效,而是作用于 stu_name 这个字段上面,实在是很邪门!

第二种方式:

使用 @IdClass 这个注解来实现,我们需要新建一个主键类,这个类需要实现 Serializable 接口,并且需要无惨构造函数,还需要重写 equals 和 hashCode 方法,具体内容如下:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class StudentUPK implements Serializable {

    private Integer stuNo;

    private String stuName;

}

这里我是使用 lombok 插件来简化代码的,当然你可以自己手写构造函数和重写方法。然后实体类 Student 的内容如下:

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

    @Id
    @Column(name = "stu_no", nullable = false, length = 11)
    private Integer stuNo;

    @Id
    @Column(name = "stu_name", nullable = false, length = 128)
    private String stuName;

    @Column(name = "stu_age", nullable = false, length = 3)
    private Integer stuAge;

    @Column(name = "class_id", nullable = false, length = 8)
    private String classId;
}

这种方式也是存在问题的,在使用 JpaRepository 的时候,这样写:public interface StudentRepository extends JpaRepository<Student, StudentUPK> ,ID 写成这主键类,本以为是可以的,但一执行 CRUD 老是会报错,到现在还没找到原因。

3. 第三种方式:

第三种方式是使用 @Embeddable 和 @EmbeddedId 注解来实现,同样是需要一个主键类,内容如下:

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
@EqualsAndHashCode
public class StudentUPK implements Serializable {

    @Column(name = "stu_no", nullable = false, length = 11)
    private Integer stuNo;

    @Column(name = "stu_name", nullable = false, length = 128)
    private String stuName;
}

主键类也是需要实现 Serializable 接口,并且需要无惨构造函数,还需要重写 equals 和 hashCode 方法。实体类 Student 的内容如下:

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

    @EmbeddedId
    private StudentUPK studentUPK;

    @Column(name = "stu_age", nullable = false, length = 3)
    private Integer stuAge;

    @Column(name = "class_id", nullable = false, length = 8)
    private String classId;
}

这里使用了 @EmbeddedId 这个注解。这种方式使用 JpaRepository 是可以的,例如写成这样:public interface StudentRepository extends JpaRepository<Student, StudentUPK> { }

然后再新建一个测试方法:

@SpringBootTest
@RunWith(SpringRunner.class)
public class StudentRepositoryTest {

    @Resource
    private StudentRepository studentRepository;

    @Test
    public void testInsert(){
        StudentUPK upk = StudentUPK.builder().stuNo(132).stuName("Rose Duan").build();
        Student student = Student.builder().studentUPK(upk).stuAge(14).classId("12312323").build();

        studentRepository.save(student);
    }

}

CRUD 的操作应该就成功了!

相关标签: Spring Data JPA