JPA 2.0 orphanRemoval = true VS on delete Cascade

Я немного запутался в атрибуте JPA 2.0 orphanRemoval.

Я думаю, что я вижу, что это необходимо, когда я использую свои инструменты генерации DB DB для создания базы данных DDL, чтобы иметь ON DELETE CASCADE для конкретного отношения.

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

Приветствия

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

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

Надеюсь, это станет более ясным.

Ответ 3

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

Ответ 4

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

Ответ 5

удаление сирот имеет тот же эффект, что и ON DELETE CASCADE в следующем сценарии: - Допустим, у нас есть простая взаимосвязь между студенческим сущностью и объектом-руководителем, где многие ученики могут быть сопоставлены с одним и тем же руководством, а в базе данных у нас есть отношение внешнего ключа между таблицей Student и Guide, так что таблица ученика имеет 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 в моем случае)

Таблица СТУДЕНТОВ: -

Идентификатор имени Dede Id_Guide

1               < 1 <

2     & Ник NBSP;   &nbsp ЕС;   1

Таблица GUIDE: -

ИДЕНТИФИКАТОР ИМЯ Зарплата

1     John     $1500

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

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

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

Ответ 6

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

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

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