Many-to-Many Using a Composite Key
student
student_course
course
id (PK) name
student_id (PK, FK) course_id (PK, FK) rating
id (PK) name
如上,现在我们希望在中间表加上一个 rating
属性,以表示某学生对某课程的评价。
很明显,上一小节谈到的 Basic Many-to-Many 是没有能力做到这一点的,简单地打上 @ManyToMany
注解并不能在中间表中加上自定义属性。
这就是为什么我们需要 Compositing Key (组合键)。
Spring Data JPA 实现组合键:
@Embeddable
@Getter
@Setter
class CourseRatingKey implements Serializable {
@Column(name = "student_id")
private Long studentId;
@Column(name = "course_id")
private Long courseId;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CourseRatingKey that = (CourseRatingKey) o;
return Objects.equals(studentId, that.studentId) && Objects.equals(courseId, that.courseId);
}
@Override
public int hashCode() {
return Objects.hash(studentId, courseId);
}
}
一个组合键类必须满足:
标记为
@Embeddable
实现
java.io.Serializable
必须实现
equals()
和hashCode()
两个方法实例域中不能出现实体类型
使用组合键:
中间表:
@Entity
@Getter
@Setter
class CourseRating {
@EmbeddedId
private CourseRatingKey id;
@ManyToOne
@MapsId("studentId")
@JoinColumn(name = "student_id")
private Student student;
@ManyToOne
@MapsId("courseId")
@JoinColumn(name = "course_id")
private Course course;
int rating;
}
@EmbeddedId
用于标记主键。@MapsId
将student
和course
的id
映射到主键(在这里是组合键)中去。我们之所以要用
@MapsId
是因为,刚刚提到的,组合键的实例域中不能出现实体类型。
接下来配置 student
和 course
:
@Entity
@Getter
@Setter
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@OneToMany(mappedBy = "course")
private Set<CourseRating> courseRating;
}
@Entity
@Getter
@Setter
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@OneToMany(mappedBy = "student")
private Set<CourseRating> courseRatings;
}
配置完成。
最后更新于