【问题标题】:Hibernate: Deleting in One-to-Many/Many-To-One failsHibernate:删除一对多/多对一失败
【发布时间】:2019-12-17 15:29:36
【问题描述】:

假设我们有三个实体:Course、Student 和 Guide。 许多学生可以访问许多课程,许多课程可以包含许多学生。这就是为什么我在Student 和Course 之间创建了bidirectional Many-To-Many-Relationship:

@Entity()
@Getter
@Setter
@ToString(exclude = "courses")
@Builder
@Table(name = "students")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

    @ManyToMany(cascade = CascadeType.REMOVE)
    @JoinTable(
            name = "courses_students",
            joinColumns = @JoinColumn(name = "students_id"),
            inverseJoinColumns = @JoinColumn(name = "courses_id"))
    private Set<Course> courses;


}

@Entity
@Builder
@Getter
@Setter
@ToString(exclude = "guide")
@Table(name="courses")
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne()
    @JoinColumn(name="guide_id")
    private Guide guide;

    @Column
    private String title;

    @ManyToMany(mappedBy = "courses")
    Set<Student> students;
}

此外,每门课程只有一位指南,但一位指南可以教授多门课程。所以在Course和Guide之间存在birectional One-to-Many/Many-to-One-Relationship,所有权在Course旁边:

@Entity
@Table(name = "guides")
@Getter
@Setter
@Builder
public class Guide {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

    @OneToMany(mappedBy = "guide")
    private List<Course> courses = new ArrayList<>();

}

当我删除所有学生时,Cascade.Remove 所有Course-entities 也会被删除,这很好。但是当我从GuideRepository 检索Guide-instances 并调用&lt;guideInstance&gt;.getCourses() 时,我得到了一个课程列表。我希望得到一个空列表,因为从CourseRepository 我什么也得不到!这里有什么问题?

为了重现该问题,我发布了创建实体的代码:

 Course java= Course.builder().title("Java").build();
    Course python= Course.builder().title("Python").build();
    Course kotlin= Course.builder().title("Kotlin").build();

    Set<Course> johnCourses=new HashSet<>();
    johnCourses.add(java);
    johnCourses.add(python);

    Set<Course> jackCourses=new HashSet<>();
    jackCourses.add(java);
    jackCourses.add(python);
    jackCourses.add(kotlin);

    Set<Course> henryCourses=new HashSet<>();
    henryCourses.add(python);
    henryCourses.add(kotlin);

    List<Course> drMorrisCourses=new ArrayList<Course>();
    drMorrisCourses.add(java);
    drMorrisCourses.add(kotlin);

    List<Course> drFerrisCourses=new ArrayList<Course>();
    drFerrisCourses.add(python);

    Guide drMorris = Guide.builder().name("Dr. Morris").courses(drMorrisCourses).build();
    Guide drFerris = Guide.builder().name("Dr. Ferris").courses(drFerrisCourses).build();

    Student john= Student.builder().name("John").courses(johnCourses).build();
    Student jack= Student.builder().name("Jack").courses(jackCourses).build();
    Student henry= Student.builder().name("Henry").courses(henryCourses).build();

    Set<Student> javaStudents=new HashSet<>();
    javaStudents.add(john);
    javaStudents.add(jack);

    Set<Student> kotlinStudents=new HashSet<>();
    kotlinStudents.add(jack);
    kotlinStudents.add(henry);

    Set<Student> pythonStudents=new HashSet<>();
    pythonStudents.add(john);
    pythonStudents.add(henry);
    pythonStudents.add(jack);

    java.setGuide(drMorris);
    kotlin.setGuide(drMorris);
    python.setGuide(drFerris);

    java.setStudents(javaStudents);
    python.setStudents(pythonStudents);
    kotlin.setStudents(kotlinStudents);

    studentRepository.save(john);
    studentRepository.save(jack);
    studentRepository.save(henry);

    courseRepository.save(java);
    courseRepository.save(kotlin);
    courseRepository.save(python);

    guideRepository.save(drMorris);
    guideRepository.save(drFerris);

现在所有实体都设置好了。要删除一名学生,我可以使用以下代码:

      List<Student> allStudents = studentRepository.findAll();
//Here I choose for example first student and delete it!        
studentrepository.delete(allStudents.get(0));

我删除了第一个Student-Entity,即John,它访问了Java课程。随着John的删除,Java课程也消失了,因为Cascase.REMOVE:

List<Course> courses =courseRepository.findAll();
courses.size() // -> only 2 because Java course entity is deleted!!!!

但是如果我调用第一个指导实体,这意味着drMorris 我可以看到drMorris 仍然有Java 课程,尽管Java course-Entity 已被删除!:

List<Guide> guides=guideRepository.findAll();
guides.get(0).getCourses //<- drMorris should not have Java Course!!!!!!!!

【问题讨论】:

  • 我们不知道,因为您没有发布重现问题的代码。但是在 ManyToXxx 关联上使用 cascade=REMOVE 总是一个坏主意。如果我删除学生 John,那么 John 访问的所有课程都不应该被删除:Jane、Jack 和 Henry 也访问了该课程,因此如果您的数据库中有正确的外键约束,那么肯定会失败并出现异常无论如何。
  • 但是您的代码没有显示您如何删除学生?

标签: java hibernate jpa spring-data-jpa one-to-many


【解决方案1】:

这是我的解决方案:

   public void deleteStudents(){
        List<Student> all = studentRepository.findAll();
       deleteStudent(all.get(2));
     }

     public void deleteStudent(Student student) {

        Set<Course> courses = student.getCourses();

         for (Course course: courses) {
             if (course.getStudents().size() == 1 ){
                 course.getGuide().getCourses().remove(course);

                 courseRepository.delete(course);
             } else {
                 course.getStudents().remove(student);
             }
         }
         studentRepository.delete(student);
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 2015-03-24
    • 1970-01-01
    • 2013-01-13
    相关资源
    最近更新 更多