Имате JPA/Hibernate, за да копирате функционалността ON DELETE SET NULL

Успях да накарам JPA/Hibernate да репликира успешно функционалността ON DELETE CASCADE (изглежда като поведението по подразбиране), но сега се опитвам да репликирам функционалността ON DELETE SET NULL и се сблъсквам с проблеми.

Това са моите два класа:

@Entity
@Table(name = "teacher")
public class Teacher
{
    @Id
    @GeneratedValue
    @Column(name = "id", nullable = false, length = 4)
    private int id;

    @OneToMany(mappedBy = "teacher")
    private List<Student> studentList;

    // ...
}

@Entity
@Table(name = "student")
public class Student
{
    @Id
    @GeneratedValue
    @Column(name = "id", nullable = false, length = 4)
    private int id;

    @ManyToOne(optional = true)
    @JoinColumn(name = "teacher_id", nullable = true)
    private Teacher teacher;

    // ...
}

Когато се опитам да изтрия учител, се появява следната грешка:

org.springframework.dao.DataIntegrityViolationException: Не може да се изпълни пакетна актуализация на JDBC; SQL [изтриване от учител, където teacher_id=?]; ограничение [null]
...
Причинено от: org.hibernate.exception.ConstraintViolationException: Не може да се изпълни пакетна актуализация на JDBC
...
Причинено от: java.sql. BatchUpdateException: Изтриване на партиден запис 0 от учител, където teacher_id='1' е прекратено. Обадете се на getNextException, за да видите причината.

Правя ли нещо нередно? Дали е нещо постижимо?

Благодаря ти.


person satoshi    schedule 30.03.2012    source източник
comment
искате ли да настроите всички колони на този запис на null? или всички полета на обекта ученик   -  person kommradHomer    schedule 02.04.2012
comment
Искам колоната teacher на student да стане null, след като teacher на student бъде изтрита от системата.   -  person satoshi    schedule 02.04.2012
comment
Не че искате да промените вашата схема за JPA, но бих бил любопитен ефектът от промяната й на ManyToMany с каскадно изтриване на таблицата за присъединяване. Трябва да изтрие асоциацията и да остави ученика.   -  person kevingallagher    schedule 05.04.2012


Отговори (3)


Изглежда, че в момента не е възможно с jpa/hibernate.

При изтриване задайте null в хибернация в @OneToMany

Решението на JBs обаче изглежда чисто:

for (Department child : parent.getChildren()) {
    child.setParentDepartment(null);
}
session.delete(parent);

Трябва също да можете да го поставите в PreRemove:

@PreRemove
private void preRemove() {
    for (Student s : studentList) {
        s.setTeacher(null);
    }
}
person kevingallagher    schedule 05.04.2012
comment
Благодаря ви, и двете решения работят перфектно. Аз лично предпочитам второто :) - person satoshi; 06.04.2012
comment
Решението @PreRemove не е преносимо. Вижте JPA спецификация раздел 3.5. По принцип методът на жизнения цикъл на преносимо приложение не трябва [...] да променя връзките в рамките на същия контекст на постоянство. - person SpaceTrucker; 06.09.2013
comment
Това работи, но когато изтрия „Ученик“ от „Учител“ и искам да добавя същия „Ученик“ към различен „Учител“ – просто не работи – „Ученик“ има нула „Учител“ в DB. - person Michał Stochmal; 28.02.2019

Ами дефинирането

@ForeignKey(name = "fk_student_teacher",
            foreignKeyDefinition = " /*FOREIGN KEY in sql that sets ON DELETE SET NULL*/")

?

person Michał Ziobro    schedule 08.06.2015
comment
Това се използва само за указване на ограничения на външен ключ в свързаната база данни, когато е в сила генерирането на схема. - person Tiny; 23.09.2015

Мисля, че най-доброто решение е потребителски SQL оператор за настройка на действие за изтриване, както следва:

CREATE TABLE table_name
(
  column1 datatype null/not null,
  column2 datatype null/not null,
  ...

  CONSTRAINT fk_column
     FOREIGN KEY (column1, column2, ... column_n)
     REFERENCES parent_table (column1, column2, ... column_n)
     ON DELETE SET NULL
);

когато потребителят изтрие ред чрез друго каскадно изтриване, където използвате препратка към таблица към този изтрит ред, не можете да използвате решение за хибернация и да върнете SQL изключение.

person M2E67    schedule 19.02.2017