JPA 2.0 orphanRemoval = true VS при удалении каскада - PullRequest
155 голосов
/ 02 декабря 2010

Я немного озадачен атрибутом JPA 2.0 orphanRemoval.

Я думаю, что вижу, что он необходим, когда я использую инструменты генерации БД моего провайдера JPA для создания базовой базы данных DDL, чтобы иметь1004 * для конкретного отношения.

Однако, если БД существует, и у нее уже есть ON DELETE CASCADE в отношении, этого недостаточно для надлежащего каскадного удаления?Что дополнительно делает orphanRemoval?

Приветствия

Ответы [ 7 ]

238 голосов
/ 02 декабря 2010

orphanRemoval не имеет ничего общего с ON DELETE CASCADE.

orphanRemoval это полностью ORM-специфическая вещь . Он помечает «дочернюю» сущность, которая будет удалена, когда на нее больше не ссылаются из «родительской» сущности, например, при удалении дочерней сущности из соответствующей коллекции родительской сущности.

ON DELETE CASCADE - это специфичная для базы данных вещь , она удаляет «дочернюю» строку в базе данных при удалении «родительской» строки.

76 голосов
/ 19 августа 2012

Пример взятой формы здесь :

Когда объект сущности Employee удаляется, операция удаления каскадно ссылается на объект сущности Address, на который ссылаются.В этом отношении orphanRemoval=true и cascade=CascadeType.REMOVE идентичны, а если указано orphanRemoval=true, CascadeType.REMOVE является избыточным.

Разница между двумя настройками заключается в ответе на разъединение отношения.Например, например, при установке в поле адреса значения null или другого объекта Address.

  • Если указано orphanRemoval=true, отключенный экземпляр Address автоматически удаляется.Это полезно для очистки зависимых объектов (например, Address), которые не должны существовать без ссылки от объекта-владельца (например, Employee).

  • Если только cascade=CascadeType.REMOVE - этоуказано, автоматическое действие не предпринимается, поскольку отключение отношения не является операцией удаления.

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

Надеюсь, это прояснит ситуацию.

44 голосов
/ 31 мая 2011

Как только вы удалите дочернюю сущность из коллекции, вы также удалите эту дочернюю сущность из БД. orphanRemoval также подразумевает, что вы не можете сменить родителей; если есть отдел, в котором есть сотрудники, то после того, как вы удалите этого сотрудника, чтобы перевести его в другой отдел, вы по неосторожности удалите этого сотрудника из БД с помощью команды flush / commit (что будет первым). Мораль заключается в том, чтобы установить для orphanRemoval значение true, если вы уверены, что дети этого родителя не будут мигрировать к другому родителю на протяжении всего своего существования. Включение orphanRemoval также автоматически добавляет REMOVE в каскадный список.

17 голосов
/ 02 декабря 2010

Эквивалентное отображение JPA для DDL ON DELETE CASCADE равно cascade=CascadeType.REMOVE.Удаление без учета означает, что зависимые объекты удаляются, когда связь с их «родительским» объектом уничтожается.Например, если дочерний элемент удален из отношения @OneToMany без явного удаления его в менеджере сущностей.

4 голосов
/ 09 сентября 2015

@ GaryK ответ абсолютно отличный, я потратил час на поиски объяснения orphanRemoval = true против CascadeType.REMOVE, и это помогло мне понять.

Подведение итогов: orphanRemoval = true работает идентично CascadeType.REMOVE ТОЛЬКО ЕСЛИ мы удаляем объект (entityManager.delete(object)) и хотим, чтобы дочерние объекты также удалялись.

В совершенно другой ситуации, когда мы выбираем некоторые данные, такие как List<Child> childs = object.getChilds(), а затем удаляем дочерний элемент (entityManager.remove(childs.get(0)), используя orphanRemoval=true, это приведет к тому, что объект, соответствующий childs.get(0), будет удален из базы данных.

3 голосов
/ 05 августа 2015

удаление сирот имеет тот же эффект, что и ON DELETE CASCADE в следующем сценарии: - Допустим, у нас есть простое отношение много-к-одному между сущностью студента и сущностью-гидом, где многие ученики могут быть сопоставлены с одним и тем же руководством, а в базе данных у нас есть связь по внешнему ключу между таблицей ученика и путеводителем, так что в таблице ученика есть id_guide как FK .

    @Entity
    @Table(name = "student", catalog = "helloworld")
    public class Student implements java.io.Serializable {
     @Id
     @GeneratedValue(strategy = IDENTITY)
     @Column(name = "id")
     private Integer id;

    @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE})
    @JoinColumn(name = "id_guide")
    private Guide guide;

// Родительский объект

    @Entity
    @Table(name = "guide", catalog = "helloworld")
    public class Guide implements java.io.Serializable {

/**
 * 
 */
private static final long serialVersionUID = 9017118664546491038L;

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;

@Column(name = "name", length = 45)
private String name;

@Column(name = "salary", length = 45)
private String salary;


 @OneToMany(mappedBy = "guide", orphanRemoval=true) 
 private Set<Student> students = new  HashSet<Student>(0);

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

    Guide guide = new Guide("John", "$1500");
    Student s1 = new Student(guide, "Roy","ECE");
    Student s2 = new Student(guide, "Nick", "ECE");
    em.persist(s1);
    em.persist(s2);

Здесь мы отображаем одно и то же руководство с двумя разными объектами учащихся, и поскольку используется CASCADE.PERSIST, граф объектов будет сохранен, как показано ниже в таблице базы данных (в моем случае MySql)

Стол СТУДЕНТА: -

ID Name Dept Id_Guide

1 Roy ECE 1

2 ник ECE 1

Таблица руководств: -

ID NAME Зарплата

1 Джон $ 1500

и теперь, если я хочу удалить одного из студентов, используйте

      Student student1 = em.find(Student.class,1);
      em.remove(student1);

и при удалении записи об ученике должна быть также удалена соответствующая запись гида, вот где атрибут CASCADE.REMOVE в сущности «Студент» входит в картинку и что он делает, он удаляет студента с идентификатором 1, а также соответствующее руководство объект (идентификатор 1). Но в этом примере есть еще один объект ученика, который сопоставлен с той же направляющей записью, и, если мы не используем атрибут orphanRemoval = true в объекте Guide, приведенный выше код удаления не будет работать.

2 голосов
/ 14 апреля 2018

Разница:
- orphanRemoval = true: дочерний объект удаляется, если на него больше нет ссылок (его родитель не может быть удален).
- CascadeType.REMOVE: «Дочерняя» сущность удаляется только тогда, когда удаляется ее «Родительская».

...