Spring Data JPA: 在双向多对多关系中进行持久化

3

我成功地在子级别(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);
}

学生列表 | Postman

学生列表

课程列表 | Postman

课程列表

学生_课程 | 透视表 + Hibernate 查询

透视表数据


如何在主表中使其工作?

这样,持久性不在CourseService中运行,而应该在StudentService中运行。

这样,我可以在Postman中编写以下内容,同时插入一名学生及其附加的课程:

{
    "name" : "John Doe",
    "courses" : [
        {
            "id" : 1
        },
                {
            "id" : 2
        }
        ]
}

当您在应用程序中发布带有课程的学生时会发生什么? - Ali D.A.
2个回答

3

你需要在Course实体中递归地应用更改(基本上与您以相反方式执行的方式相同):

@ManyToMany(mappedBy = "courses", fetch = FetchType.LAZY, cascade = {
    CascadeType.PERSIST,
    CascadeType.MERGE
})
private Set<Student> students = new HashSet<>();

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;

你为什么要这样做?那会引入大量的注释。它难以阅读,也难以维护。 - Andronicus
我已经提到过了,最好将它们放在一个实体中使用,而Cascade则可以帮助处理其余部分。我只是这样回答的,它也能够工作。 - Tarun
如果没有任何优点,解决方案只会更糟,为什么还要费心呢... - Andronicus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接