Spring Data JPA:在两个方向上保持多对可能的关系
Posted
技术标签:
【中文标题】Spring Data JPA:在两个方向上保持多对可能的关系【英文标题】:Spring Data JPA : persist a many to may relationship in both directions 【发布时间】:2020-09-25 20:00:20 【问题描述】:我设法在子端保持了多对多关系 (mappedBy
),它工作得很好,如下所示:
学生实体(所有者)
package com.main.manytomany.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "students")
@Getter
@Setter
@NoArgsConstructor
public class Student
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@JsonIgnore
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable
(
name = "students_courses",
joinColumns =
@JoinColumn
(
name = "student_id",
referencedColumnName = "id",
nullable = false,
updatable = false
)
,
inverseJoinColumns =
@JoinColumn
(
name = "course_id",
referencedColumnName = "id",
nullable = false,
updatable = false
)
)
private Set<Course> courses = new HashSet<>();
课程实体(儿童)
package com.main.manytomany.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "courses")
@Getter@Setter
@NoArgsConstructor
public class Course
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "courses", fetch = FetchType.LAZY)
private Set<Student> students = new HashSet<>();
学生服务
package com.main.manytomany.services;
import com.main.manytomany.models.Student;
import com.main.manytomany.repositories.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentService
private final StudentRepository studentRepository;
@Autowired
public StudentService(StudentRepository studentRepository)
this.studentRepository = studentRepository;
public List<Student> findAll()
return this.studentRepository.findAll();
public Student getOneById(Long id)
return this.studentRepository.getOne(id);
public void store(Student student)
this.studentRepository.save(student);
课程服务
package com.main.manytomany.services;
import com.main.manytomany.models.Course;
import com.main.manytomany.models.Student;
import com.main.manytomany.repositories.CourseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class CourseService
private final CourseRepository courseRepository;
private final StudentService studentService;
@Autowired
public CourseService(CourseRepository courseRepository, StudentService studentService)
this.courseRepository = courseRepository;
this.studentService = studentService;
public List<Course> findAll()
return this.courseRepository.findAll();
public void store(Course course)
course.getStudents()
.addAll(course
.getStudents()
.stream()
.map(s ->
Student student = studentService.getOneById(s.getId());
student.getCourses().add(course);
return student;
).collect(Collectors.toList()));
this.courseRepository.save(course);
学生控制器 |贴图
@PostMapping
public ResponseEntity<Void> create(@RequestBody Student student)
this.studentService.store(student);
return new ResponseEntity<>(HttpStatus.CREATED);
课程控制器 |贴图
@PostMapping
public ResponseEntity<Void> create(@RequestBody Course course)
this.courseService.store(course);
return new ResponseEntity<>(HttpStatus.CREATED);
学生名单 |邮递员
课程列表 |邮递员
Students_Courses |数据透视表 + 休眠查询
我怎样才能让它在所有者表中工作?
这样一来,持久性不会在 CourseService 中运行,而是应该在StudentService中运行。
所以在 Postman 中,我会写一些类似的东西来指导学生,连同他的附加课程:
"name" : "John Doe",
"courses" : [
"id" : 1
,
"id" : 2
]
【问题讨论】:
当您向学生发布课程时,您的应用会发生什么情况? 【参考方案1】:不使用 - mappedBy
很好用(如果我们想保留一个实体作为父实体),您可以在两个表中使用 @JoinTable
并定义相应的方法来保存数据。
因此,更改下面的映射和 StudentService
中的 store
方法以保存课程将起作用。
@JsonIgnore
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable
(
name = "students_courses",
joinColumns =
@JoinColumn
(
name = "course_id",
referencedColumnName = "id",
nullable = false,
updatable = false
)
,
inverseJoinColumns =
@JoinColumn
(
name = "student_id",
referencedColumnName = "id",
nullable = false,
updatable = false
)
)
private Set<Student> students = new HashSet<>();
示例:
@ManyToMany(fetch=FetchType.LAZY,cascade=CascadeType.PERSIST,CascadeType.DETACH,CascadeType.REFRESH,CascadeType.MERGE)
@JoinTable(name="course_student", joinColumns=@JoinColumn(name="course_id"), inverseJoinColumns=@JoinColumn(name="student_id"))
private List<Student> students;
@ManyToMany(fetch=FetchType.LAZY,cascade=CascadeType.PERSIST,CascadeType.DETACH,CascadeType.REFRESH,CascadeType.MERGE)
@JoinTable(name="course_student", joinColumns=@JoinColumn(name="student_id"), inverseJoinColumns=@JoinColumn(name="course_id"))
private List<Course> courses;
【讨论】:
你为什么要这样做?这引入了大量的注释。它不可读且难以维护 我已经提到了....最好在一个实体中使用它,Cascade
有助于其余的。我就是这样回答的,也行。
如果没有专业人士,解决方案只会更糟,为什么还要麻烦......【参考方案2】:
您需要在Course
实体中级联更改(与您在另一个方向上所做的几乎相同):
@ManyToMany(mappedBy = "courses", fetch = FetchType.LAZY, cascade =
CascadeType.PERSIST,
CascadeType.MERGE
)
private Set<Student> students = new HashSet<>();
【讨论】:
以上是关于Spring Data JPA:在两个方向上保持多对可能的关系的主要内容,如果未能解决你的问题,请参考以下文章
如何与 Spring Data REST 和 JPA 保持双向关系?
使用spring boot和spring data jpa时一对多关系的奇怪行为
spring data jpa 自定义sql in查询加判断
外键在一对多关系中始终为空 - Spring Boot Data with JPA