Удаление экземпляра объекта с отношением MANY_TO_MANY без каскадирования завершается ошибкой

У меня есть два класса (студенты и курсы), которые имеют отношения «многие ко многим». Экземпляры одного из них могут существовать без другого. Поэтому я удалил атрибут каскада в JPA-аннотации: @ManyToMany(cascade = CascadeType.ALL)

Когда я пытаюсь удалить студента, я получаю это сообщение об ошибке.

Что я делаю неправильно?

org.hibernate.exception.ConstraintViolationException: не удалось удалить: [com.Student#4]; вложенным исключением является javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: не удалось удалить: [com.Student#4]

Это Hibernate-выход:

Hibernate: удалить из студента, где id=? а версия=? 2011-09-19 15:25:10,317 [http-8080-3] ОШИБКА org.hibernate.util.JDBCExceptionReporter — невозможно удалить или обновить родительскую строку: ограничение внешнего ключа не работает (database.student_course, КОНСТРЕЙНТ FKF8A06F72970A31AF ВНЕШНИЙ КЛЮЧ (students ) ССЫЛКИ students (id))

Это соответствующие части обоих классов:

@RooJavaBean
@RooToString
@RooEntity
public class Student{

    @ManyToMany
    private Set<Course> courses= new HashSet<Course>();
}

@RooJavaBean
@RooToString
@RooEntity
public class Course {

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

person Hedge    schedule 19.09.2011    source источник
comment
Каково ваше намерение? Если вы удаляете Student, вы определенно хотите обновить Set во всех Course, верно? Попробуйте восстановить каскад, но используя CascadeType.REMOVE   -  person millhouse    schedule 20.09.2011
comment
Можете ли вы попробовать очистить коллекцию курсов перед удалением студента. Я не думаю, что каскад здесь поможет - каскад предназначен для удаления курса при удалении студента. В вашем случае причиной проблемы являются строки в таблице сопоставления.   -  person gkamal    schedule 20.09.2011


Ответы (1)


Я собирался предложить добавить метод detachFromCourses() к вашему Student, который перебирает courses, удаляя this. Вы бы назвали это непосредственно перед удалением файла Student. Но это уродливо и не очень хорошо сочетается со Spring Roo.

Могу ли я предложить изучить создание JPA Entity Listener, подключенного к событию @PreRemove JPA. ? Затем вы можете сохранить свою модель предметной области и свои контроллеры свободными от вещей, связанных с базой данных. Затем ваш Entity Listener может просто сделать:

@PreRemove
void onPreRemove(Object o) {
    if (o instanceof Student) {
        // Remove all the course references to this Student
        Student s = (Student) o;
        for (Course c : s.getCourses()) {
            c.getStudents().remove(s);
        }
    }
}
person millhouse    schedule 22.09.2011