Hibernate的许多一对多级联删除

问题描述 投票:21回答:3

我有3代表在我的数据库:StudentsCoursesStudents_Courses

学生可以有多种课程和课程可以有多个学生。有StudentsCourses之间的许多一对多的关系。

我有三种情况:我的项目,并添加到我的Courses表的课程。

  • (一)当我增加一个用户,它被保存的很好,
  • (b)当我添加课程为学生,它会在User_Courses新行 - 再次,预期的行为。
  • (三)当我试图删除学生,则删除在StudentsStudents_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<Courses> Courseses = new HashSet<Courses>(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<Courses> getCourseses() {
        return this.Courseses;
    }

     public void setCourseses(Set<Courses> Courseses) {
        this.Courseses = Courseses;
    }

    }


    @Entity
@Table(name = "Courses")
public class Courses implements java.io.Serializable {

  private Integer CourseID;
    private String CourseName;
     private Set<Students> Studentses = new HashSet<Students>(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<Students> getStudentses() {
        return this.Studentses;
    }

    public void setStudentses(Set<Students> Studentses) {
        this.Studentses = Studentses;
    }

    }

我怎样才能达到我所描述?我不能在网上找到任何合理的文档。

java sql hibernate annotations many-to-many
3个回答
19
投票

我发现了正确的映射(和测试,与具有广泛的情况下的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<Course> 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<Student> students = new HashSet<>();

大量的JUnit测试证实:

  • 我可以添加课程,学生和反之亦然完美
  • 如果我从一个学生删除过程中,当然不会被删除
  • 反之亦然
  • 如果我删除学生,所有课程都拆下来,但他们仍然在坚持的数据库(其他学生)
  • 反之亦然

16
投票

基于你告诉我你不想级联= CascadeType.ALL对学生的getCourseses方法。请记住,Hibernate的级联是不一样的数据库级联。即使你没有任何级联,则Hibernate将删除Students_Courses记录。

想Hibernate的级联的最好的办法是,如果你调用一个实体的操作和操作级联列表中列出则该操作将在所有子实体的调用。

例如,当你调用删除学生,因为删除是在课程级联列表,Hibernate会删除每个由学生引用的课程实体。这就是为什么你看到的病程记录消失。

不要担心数据库的级联,Hibernate会照顾那些自身。


0
投票

你只需要删除级联= CascadeType.ALL在Student类唯一没有改变是必需的课程班

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

这意味着同时删除所有者类记录不会删除非所有者的记录。

在此之后,在删除它只会从学生表和student_course删除。当然,表中的数据保持不变。

© www.soinside.com 2019 - 2024. All rights reserved.