簡體   English   中英

Hibernate多對多級聯刪除

[英]Hibernate many-to-many cascading delete

我的數據庫中有3個表: StudentsCoursesStudents_Courses Courses

學生可以有多個課程,課程可以有多個學生。 StudentsCourses之間存在多對多的關系。

我的項目有3個案例, Courses表添加到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<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;
    }

    }

我怎樣才能實現我所描述的內容? 我在網上找不到任何合理的文件。

在類似的場景中,我找到了正確的映射(並使用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測試證實:

  • 我可以為學生添加課程,反之亦然
  • 如果我從學生中刪除課程,則不會刪除課程
  • 反之亦然
  • 如果我刪除了一名學生,所有課程都是分離的,但在數據庫中仍然存在(對其他學生)
  • 反之亦然

基於你告訴我的內容,你不希望在Student的getCourseses方法中使用cascade = CascadeType.ALL。 請記住,Hibernate級聯與數據庫級聯不同。 即使您沒有任何級聯,Hibernate也會刪除Students_Courses記錄。

考慮Hibernate級聯的最佳方法是,如果在實體上調用操作並且該操作在級聯列表中列出,則將在所有子實體上調用該操作。

例如,當您在學生上調用delete時,由於刪除位於課程的級聯列表中,因此Hibernate將在該學生引用的每個課程實體上調用delete。 這就是為什么你看到課程記錄消失的原因。

不要擔心數據庫級聯,Hibernate會自己處理這些問題。

您只需要在Student類中刪除cascade = CascadeType.ALL ,但Courses類中不需要進行任何更改

並添加以下代碼cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.DETACH} ..

這意味着在刪除所有者類記錄時,它不會刪除非所有者記錄。

在此之后,在刪除時,它將僅從Student表和student_course中刪除。 課程表數據保持不變。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM