cot_shaurma
@cot_shaurma
Java и всего понемногу

Почему Hibernate разрешает удалять сущность, на которую ссылается FK?

В приложении я использую Spring Data и Hibernate. База данных HSQLDB.

Есть таблицы students и сourses, связанные отношением ManyToMany. Эти отношения хранятся в таблице students_courses:
CREATE TABLE students
(
    id    INTEGER GENERATED BY DEFAULT AS SEQUENCE global_seq PRIMARY KEY,
    name  VARCHAR(255) NOT NULL,
);

CREATE TABLE courses
(
    id    INTEGER GENERATED BY DEFAULT AS SEQUENCE global_seq PRIMARY KEY,
    name  VARCHAR(255) NOT NULL,
);

CREATE TABLE students_courses
(
    student_id INTEGER NOT NULL,
    course_id   INTEGER NOT NULL,
    FOREIGN KEY (student_id) REFERENCES students (id),
    FOREIGN KEY (course_id) REFERENCES courses (id) ON DELETE CASCADE
);


Я хочу, чтобы нельзя было удалить студента, который уже участвует в каких-то курсах. Именно поэтому вот здесь: FOREIGN KEY (student_id) REFERENCES students (id) отсутствует ON DELETE CASCADE.

Я пытаюсь удалить студента с курсами из консоли HSQLDB и получаю ожидаемую ошибку: integrity constraint violation: foreign key no action; SYS_FK_10323 table: students_courses. То есть всё работает нормально. Но когда я пытаюсь удалить студента при помощи вызова delete() вот в таком репозитории:

@Repository
@Transactional(readOnly = true)
public interface StudentRepository extends JpaRepository<Student, Integer> {
    @Transactional
    @Modifying
    @Query("DELETE FROM Student s WHERE s.id=:id")
    int delete(@Param("id") int id);
}


то этот код срабатывает и не бросает ошибку! Причём я проверял - студент реально удаляется, поведение такое, как будто установлен ON DELETE CASCADE, хотя это не так. Как мне заставить Hibernate выбрасывать ошибку и не удалять сущность, на которую ссылается FK?
  • Вопрос задан
  • 536 просмотров
Решения вопроса 1
cot_shaurma
@cot_shaurma Автор вопроса
Java и всего понемногу
Я нашёл ответ на этот вопрос на стеке.
Суть в том, что Hibernate при удалении сущности со связью ManyToMany всегда сначала удаляет её связи, а потом уже её саму. Именно поэтому никакой ошибки и не возникает.
Ссылка
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
azerphoenix
@azerphoenix Куратор тега Java
Java Software Engineer
Добрый день!
Наверное, помимо ограничений на уровне БД можно использовать проверку средствами Java. Т.е. создать метод, который проверяет наличие курсов у юзера и выбрасывает соответствующее исключение. Соответственно, исключение будет выброшено до вызова метода delete() и будет выброшено то исключение, которе вам нужно.
Я конечно не отвечу вам наверняка, но думаю этот ответ будет для вас полезен
https://stackoverflow.com/questions/14875793/jpa-h...

JPA does offer possibility to cascade operations (merge, persist, refresh, remove) to associated entities. Logic is in JPA and does not utilize database cascades.
There is no JPA standard compliant way to do cascades with database cascades.

Т.е. скорее всего вы каскады не указали при создании сущности ManyToMany. Проверьте ваш код

Дополнено:
There is no clean cut means to do this in JPA. The following will get you what you want... You can use CascadeType.DELETE, however this annotation only applies to the objects in the EntityManager, not the database. You want to be sure that ON DELETE CASCADE is added to the database constraint. To verify, you can configure JPA to generate a ddl file. Take a look at the ddl file, you'll notice that ON DELETE CASCADE is not part of the constraint. Add ON DELETE CASCADE to actual SQL in the ddl file, then update your database schema from the ddl. This will fix your problem .
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы