Hibernate多对多级联删除

我的数据库中有3个表: StudentsCoursesStudents_Courses Courses

学生可以有多个课程,课程可以有多个学生。 StudentsCourses之间存在多对多的关系。

我的项目和案例中有3个案例已添加到我的Courses表中。

  • (a)当我添加一个用户时,它被保存得很好,
  • (b)当我为学生添加课程时,它会在User_Courses创建新行 – 再次,预期的行为。
  • (c)当我试图删除学生时,它删除了StudentsStudents_Courses Courses的相应记录,但它也删除了不需要的Courses记录。 即使我在课程中没有任何用户,我也希望课程能够在那里。

下面是我的表和注释类的代码。

  CREATE TABLE `Students` ( `StudentID` INT(11) NOT NULL AUTO_INCREMENT, `StudentName` VARCHAR(50) NOT NULL PRIMARY KEY (`StudentID`) ) CREATE TABLE `Courses` ( `CourseID` INT(11) NOT NULL AUTO_INCREMENT, `CourseName` VARCHAR(50) NOT NULL PRIMARY KEY (`CourseID`) ) CREATE TABLE `Student_Courses` ( `StudentId` INT(10) NOT NULL DEFAULT '0', `CourseID` INT(10) NOT NULL DEFAULT '0', PRIMARY KEY (`StudentId`, `CourseID`), INDEX `FK__courses` (`CourseID`), INDEX `StudentId` (`StudentId`), CONSTRAINT `FK__courses` FOREIGN KEY (`CourseID`) REFERENCES `courses` (`CourseID`) ON DELETE NO ACTION, CONSTRAINT `FK_students` FOREIGN KEY (`StudentId`) REFERENCES `students` (`StudentId`) ) 

这是Hibernate生成的Java代码:

 @Entity @Table(name = "Students") public class Students implements java.io.Serializable { private Integer StudentID; private String Students; private Set Courseses = new HashSet(0); public Students() { } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "StudentID", unique = true, nullable = false) public Integer getStudentID() { return this.StudentID; } public void setStudentID(Integer StudentID) { this.StudentID = StudentID; } @Column(name = "Students", nullable = false, length = 50) public String getCampaign() { return this.Students; } public void setCampaign(String Students) { this.Students = Students; } @ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY) @JoinTable(name = "Student_Courses", joinColumns = { @JoinColumn(name = "StudentId", nullable = false, updatable = false)}, inverseJoinColumns = { @JoinColumn(name = "CourseID", nullable = false, updatable = false)}) public Set getCourseses() { return this.Courseses; } public void setCourseses(Set Courseses) { this.Courseses = Courseses; } } @Entity @Table(name = "Courses") public class Courses implements java.io.Serializable { private Integer CourseID; private String CourseName; private Set Studentses = new HashSet(0); public Courses() { } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "CourseID", unique = true, nullable = false) public Integer getCourseID() { return this.CourseID; } public void setCourseID(Integer CourseID) { this.CourseID = CourseID; } @Column(name = "CourseName", nullable = false, length = 100) public String getCourseName() { return this.CourseName; } public void setCourseName(String CourseName) { this.CourseName = CourseName; } @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "Courseses") public Set getStudentses() { return this.Studentses; } public void setStudentses(Set Studentses) { this.Studentses = Studentses; } } 

我怎样才能实现我所描述的内容? 我在网上找不到任何合理的文件。

我在类似的场景中找到了正确的映射(并使用JUnit测试了广泛的情况)。 我不认为我会发布测试代码,因为它需要很长时间才能适应这个例子。 无论如何,关键是:

  • 不使用mappedBy属性作为注释,使用连接列
  • 列出可能的CascadeTypes不包括REMOVE

在OP的例子中

 @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST }, targetEntity = Course.class) @JoinTable(name = "XTB_STUDENTS_COURSES", inverseJoinColumns = @JoinColumn(name = "COURSE_ID", nullable = false, updatable = false), joinColumns = @JoinColumn(name = "STUDENT_ID", nullable = false, updatable = false), foreignKey = @ForeignKey(ConstraintMode.CONSTRAINT), inverseForeignKey = @ForeignKey(ConstraintMode.CONSTRAINT)) private final Set courses = new HashSet<>(); @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST }, targetEntity = Student.class) @JoinTable(name = "XTB_STUDENTS_COURSES", joinColumns = @JoinColumn(name = "COURSE_ID", nullable = false, updatable = false), inverseJoinColumns = @JoinColumn(name = "STUDENT_ID", nullable = false, updatable = false), foreignKey = @ForeignKey(ConstraintMode.CONSTRAINT), inverseForeignKey = @ForeignKey(ConstraintMode.CONSTRAINT)) private final Set students = new HashSet<>(); 

广泛的JUnit测试证实:

  • 我可以为学生添加课程,反之亦然
  • 如果我从学生中删除课程,则不会删除该课程
  • 反之亦然
  • 如果我删除了一名学生,所有课程都是分离的,但在数据库中仍然存在(对其他学生)
  • 反之亦然

基于你告诉我的内容,你不希望在Student的getCourseses方法中使用cascade = CascadeType.ALL。 请记住,Hibernate级联与数据库级联不同。 即使您没有任何级联,Hibernate也会删除Students_Courses记录。

考虑Hibernate级联的最佳方法是,如果在实体上调用操作并且该操作在级联列表中列出,则将在所有子实体上调用该操作。

例如,当您在Student上调用delete时,由于delete位于Courses的级联列表中,因此Hibernate将在该学生引用的每个Course实体上调用delete。 这就是为什么你看到课程记录消失的原因。

不要担心数据库级联,Hibernate会自己处理这些问题。

您只需要在Student类中删除cascade = CascadeType.ALL ,但Courses类中不需要进行任何更改

并添加以下代码cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.DETACH} ..

这意味着在删除所有者类记录时,它不会删除非所有者记录。

在此之后,On Delete它将仅从Student表和student_course中删除。 课程表数据保持不变。