休眠中ManyToMany关系的无限递归

Posted

技术标签:

【中文标题】休眠中ManyToMany关系的无限递归【英文标题】:Infinite Recursion on ManyToMany relationship on hibernate 【发布时间】:2020-04-14 08:23:45 【问题描述】:

我正在尝试在 Java 中创建双向 ManyToMany 模型,我在数据库中插入数据没有问题,但是当我尝试从这些表中检索数据时,它开始无限递归......我尝试了这个@中的解决方案987654321@ 但它们都不适合我,也许我把注释放在了错误的地方。

我需要找到 1 名学生以及分配给给定学生的课程是什么。

数据库

模型

学生

@Component
@Entity
@Table(name="Student")
public class Student 

    @Id
    @Column(name="student_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @Column(name="student_name")
    private String name;

    @Column(name="student_address")
    private String address;

    @Column(name="student_email")
    private String email;

    @Column(name="student_username")
    private String username;

    @Column(name="student_password")
    private String password;

    @JsonManagedReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy="pk.student")
    private Set<StudentCourse> studentCourses;

    public Student() 
        studentCourses = new HashSet<StudentCourse>(0);
    

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getAddress() 
        return address;
    

    public void setAddress(String address) 
        this.address = address;
    

    public String getEmail() 
        return email;
    

    public void setEmail(String email) 
        this.email = email;
    

    public String getUsername() 
        return username;
    

    public void setUsername(String username) 
        this.username = username;
    

    public String getPassword() 
        return password;
    

    public void setPassword(String password) 
        this.password = password;
    

    public Set<StudentCourse> getCourses() 
        return studentCourses;
    

    public void setCourses(Set<StudentCourse> studentCourses) 
        this.studentCourses = studentCourses;
    



课程

@Component
@Entity
@Table(name="Course")
public class Course 

    @Id
    @Column(name="course_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    @Column(name="course_name")
    private String name;
    @Column(name="course_schedule")
    private String schedule;    
    @ManyToOne
    @JoinColumn(name = "teacher_id")
    private Teacher teacher;

    @JsonBackReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy="pk.course")
    private Set<StudentCourse> studentCourses = new HashSet<StudentCourse>(0);

    public Course() 

    


    public Teacher getTeacher() 
        return teacher;
    

    public void setTeacher(Teacher teacher) 
        this.teacher = teacher;
    

    public Long getId() 
        return id;
    


    public void setId(Long id) 
        this.id = id;
    


    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getSchedule() 
        return schedule;
    

    public void setSchedule(String schedule) 
        this.schedule = schedule;
    

    public Set<StudentCourse> getStudentCourses() 
        return studentCourses;
    

    public void setStudentCourses(Set<StudentCourse> studentCourses) 
        this.studentCourses = studentCourses;
    



学生课程

@Component
@Entity
@Table(name="Student_Course")
@AssociationOverrides(
    @AssociationOverride(name = "pk.student", 
        joinColumns = @JoinColumn(name = "student_id")),
    @AssociationOverride(name = "pk.course", 
        joinColumns = @JoinColumn(name = "course_id")) )
public class StudentCourse implements java.io.Serializable 

    @EmbeddedId
    private StudentCourseId pk = new StudentCourseId();

    public StudentCourseId getPk() 
        return pk;
    

    public void setPk(StudentCourseId pk) 
        this.pk = pk;
    

    @Transient
    public Student getStudent() 
        return getPk().getStudent();
    

    public void setStudent(Student student) 
        getPk().setStudent(student);
    

    @Transient
    public Course getCourse() 
        return getPk().getCourse();
    

    public void setCourse(Course course) 
        getPk().setCourse(course);
    



StudentCourseId

@Embeddable
public class StudentCourseId implements java.io.Serializable 


    @ManyToOne
    private Student student;
    @ManyToOne
    private Course course;

    public Student getStudent() 
        return student;
    
    public void setStudent(Student student) 
        this.student = student;
    
    public Course getCourse() 
        return course;
    
    public void setCourse(Course course) 
        this.course = course;
    

    public boolean equals(Object o) 
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        StudentCourseId that = (StudentCourseId) o;

        if (student != null ? !student.equals(that.student) : that.student != null) return false;
        if (course != null ? !course.equals(that.course) : that.course != null)
            return false;

        return true;
    

    public int hashCode() 
        int result;
        result = (student != null ? student.hashCode() : 0);
        result = 31 * result + (course != null ? course.hashCode() : 0);
        return result;
    

服务

//find a student by its ID
public Optional<Student> getStudentById(Long studentID) throws SQLException

    return studentRepo.findById(studentID);

控制器

//find a student by its ID
@GetMapping("/findStudent/studentID")
public ResponseEntity<?> getStudentById(@PathVariable Long studentID)      
    student = sts.getStudentById(studentID).orElse(new Student());
    return new ResponseEntity<>(student, HttpStatus.OK);

我的 Json 响应

在“studentCourses”下,我希望我有这个学生被分配到的课程列表,但我得到的只是同一个学生的无限递归......

提前致谢。

【问题讨论】:

请同时添加Teacher 实体类。当您获取Course 列表时,我怀疑这与Teacher 类有关。 尝试将@ManyToOne(fetch = FetchType.LAZY) 添加到StudentCourseId => Student 和Course。 我稍后再试试,谢谢!! 【参考方案1】:

使用@JsonIdentityInfo 让它工作,并没有改变类之间的关系。

课程

@Component
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@Entity
@Table(name="Course")
public class Course 

    @Id
    @Column(name="course_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    @Column(name="course_name")
    private String name;
    @Column(name="course_schedule")
    private String schedule;    
    @ManyToOne
    @JoinColumn(name = "teacher_id")
    private Teacher teacher;

    @OneToMany(fetch = FetchType.LAZY, mappedBy="pk.course")
    private Set<StudentCourse> studentCourses = new HashSet<StudentCourse>(0);

    public Course() 

    

    /*
    @ManyToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name="teacher_id")
    public Teacher getTeacher() 
        return teacher;
    
*/

    public Teacher getTeacher() 
        return teacher;
    

    public void setTeacher(Teacher teacher) 
        this.teacher = teacher;
    

    public Long getId() 
        return id;
    


    public void setId(Long id) 
        this.id = id;
    


    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getSchedule() 
        return schedule;
    

    public void setSchedule(String schedule) 
        this.schedule = schedule;
    

    public Set<StudentCourse> getStudentCourses() 
        return studentCourses;
    

    public void setStudentCourses(Set<StudentCourse> studentCourses) 
        this.studentCourses = studentCourses;
    



学生

@Component
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@Entity
@Table(name="Student")
public class Student 

@Id
@Column(name="student_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;

@Column(name="student_name")
private String name;

@Column(name="student_address")
private String address;

@Column(name="student_email")
private String email;

@Column(name="student_username")
private String username;

@Column(name="student_password")
private String password;

@OneToMany(fetch = FetchType.LAZY, mappedBy="pk.student")
private Set<StudentCourse> studentCourses;

public Student() 
    studentCourses = new HashSet<StudentCourse>(0);


public Long getId() 
    return id;


public void setId(Long id) 
    this.id = id;


public String getName() 
    return name;


public void setName(String name) 
    this.name = name;


public String getAddress() 
    return address;


public void setAddress(String address) 
    this.address = address;


public String getEmail() 
    return email;


public void setEmail(String email) 
    this.email = email;


public String getUsername() 
    return username;


public void setUsername(String username) 
    this.username = username;


public String getPassword() 
    return password;


public void setPassword(String password) 
    this.password = password;


public Set<StudentCourse> getCourses() 
    return studentCourses;


public void setCourses(Set<StudentCourse> studentCourses) 
    this.studentCourses = studentCourses;




【讨论】:

以上是关于休眠中ManyToMany关系的无限递归的主要内容,如果未能解决你的问题,请参考以下文章

休眠 Spring:@ManyToMany DataIntegrityViolationException ConstraintViolationException

休眠 - 多对多关系中的级联删除

如何在 Kotlin 中使用 JPA ManyToMany 双向关系

注释 ConcurrentHashMap 时,在休眠中“非法尝试将非集合映射为 @OneToMany、@ManyToMany 或 @CollectionOfElements”

使用 @ManyToMany 时出现 ***Error

具有多个多对多关系的休眠批处理事务