Подтвердить что ты не робот

Снятие спящего режима во многих случаях во многих случаях

У меня есть 3 таблицы в моей базе данных: Students, Courses и Students_Courses

У студентов может быть несколько курсов, и курсы могут иметь несколько студентов. Между Students и Courses существует взаимосвязь "многие-ко-многим".

У меня есть 3 случая для моего проекта и курсы, добавленные в мою таблицу Courses.

  • (a) Когда я добавляю пользователя, он получает сохраненный штраф,
  • (b) Когда я добавляю курсы для учащегося, он создает новые строки в User_Courses - снова, ожидаемое поведение.
  • (c) Когда я пытаюсь удалить ученика, он удаляет соответствующие записи в Students и Students_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`)
)

Это код Java, сгенерированный Hibernate:

@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;
    }

    }

Как я могу достичь того, что я описал? Я не нашел никакой разумной документации в Интернете.

4b9b3361

Ответ 1

Я нашел правильное сопоставление (и проверил, что с 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 подтвердило, что:

  • Я могу добавлять курсы для студентов и наоборот безупречно
  • Если я удалю курс со студента, курс не будет удален
  • И наоборот
  • Если я удаляю ученика, все курсы отделяются, но они все еще сохраняются (для других студентов) в базе данных.
  • И наоборот

Ответ 2

На основании того, что вы сказали мне, вы не хотите, чтобы cascade = CascadeType.ALL применял метод getCourseses в Student. Имейте в виду, что каскады Hibernate не совпадают с каскадами базы данных. Даже если у вас нет каскадов, тогда Hibernate удалит запись Students_Courses.

Лучший способ думать о каскадах Hibernate заключается в том, что если вы вызываете операцию над сущностью и эта операция указана в каскадном списке, тогда эта операция будет вызываться для всех дочерних объектов.

Например, когда вы вызываете delete на Student, так как delete находится в каскадном списке для курсов, Hibernate будет вызывать delete в каждом из объектов курса, на которые ссылается этот ученик. Вот почему вы видите, как исчезают записи курса.

Не беспокойтесь о каскадах базы данных, Hibernate позаботится об этом самостоятельно.