orphanremoval hibernate что это

Удаление объектов с помощью Hibernate

Краткое руководство по удалению сущности в спящем режиме.

1. Обзор

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

Мы используем JPA и только отступаем назад и используем Hibernate native API для тех функций, которые не стандартизированы в JPA.

2. Различные способы удаления объектов

Объекты могут быть удалены в следующих сценариях:

В оставшейся части статьи мы подробно рассмотрим эти моменты.

3. Удаление С помощью Диспетчера сущностей

Удаление с помощью EntityManager – это самый простой способ удаления экземпляра сущности:

В примерах этой статьи мы используем вспомогательный метод для очистки и очистки контекста персистентности при необходимости:

Обратите внимание, что удаленный экземпляр повторно сохраняется, если к нему применяется операция PERSIST . Распространенной ошибкой является игнорирование того, что операция PERSIST была применена к удаленному экземпляру (обычно потому, что она каскадируется из другого экземпляра во время сброса), поскольку раздел 3.2.2 из спецификации JPA следует, что такой экземпляр должен быть сохранен снова в таком случае.

Мы проиллюстрируем это, определив ассоциацию @ManyToOne из Foo в Bar :

4. Каскадное Удаление

Удаление может быть каскадно передано дочерним сущностям при удалении родителей:

5. Изъятие детей-сирот

Директива orphanRemoval объявляет, что связанные экземпляры сущностей должны быть удалены, когда они не связаны с родительским объектом или, что эквивалентно, когда родительский объект удален.

Мы покажем это, определив такую ассоциацию от Bar до Baz:

Затем экземпляр Baz удаляется автоматически, когда он удаляется из списка родительского экземпляра Bar :

6. Удаление с помощью оператора JPQL

Hibernate поддерживает операции удаления в стиле DML:

7. Удаление С Помощью Собственных Запросов

Иногда нам нужно вернуться к собственным запросам, чтобы достичь чего-то, что не поддерживается Hibernate или специфично для поставщика баз данных. Мы также можем удалять данные в базе данных с помощью собственных запросов:

8. Мягкое Удаление

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

Чтобы продемонстрировать это, мы добавим аннотацию @Where и столбец с именем DELETED в сущность Foo :

Следующий тест подтверждает, что все работает так, как ожидалось:

9. Заключение

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

Источник

Vlad Mihalcea

Posted on July 8, 2020 by vladmihalcea

How does orphanRemoval work with JPA and Hibernate

If you are trading Stocks and Crypto using Revolut, then you are going to love RevoGain!

Introduction

In this article, we are going to see how the JPA and Hibernate orphanRemoval mechanism allows us to trigger an entity child remove operation upon disassociating the child entity reference from the child collection on the parent side.

Domain Model

We are going to use a Post and a PostComment entity that forms a one-to-many table relationship:

orphanremoval hibernate что это. Смотреть фото orphanremoval hibernate что это. Смотреть картинку orphanremoval hibernate что это. Картинка про orphanremoval hibernate что это. Фото orphanremoval hibernate что это

The @ManyToOne annotation in the PostComment entity map the post_id Foreign Key column that forms the one-to-many table relationship between the parent post and the post_comment child tables:

And the Post entity is mapped as follows:

The comments collection is mapped using the @OneToMany annotation, and the mappedBy attribute instructs the JPA provider that the post property in the PostComment child entity manages the underlying Foreign Key column.

The orphanRemoval attribute is going to instruct the JPA provider to trigger a remove entity state transition when a PostComment entity is no longer referenced by its parent Post entity.

Because we have a bidirectional one-to-many association, we need to make sure that both sides of the association are in sync, and for this reason, we created the addComment and removeComment methods to synchronize both ends upon adding or removing a new child entity. Check out this article for more details.

JPA and Hibernate CascadeType.PERSIST mechanism

Let’s create a Post entity with two PostComment child entities:

Because the CascadeType.ALL strategy includes the CascadeType.PERSIST option, when calling persist and the post entity, Hibernate is going to persist both the Post and the two PostComment child entities, as illustrated by the generated INSERT statements:

JPA and Hibernate orphanRemoval mechanism

If we load the Post entity along with its two PostComment child entities and remove the first PostComment :

Hibernate is going to execute the following SQL statements:

Because the removeComment method removes the PostComment reference from the comments collection, the orphanRemoval mechanism is going to trigger a remove on the PostComment entity, and a DELETE statement is executed.

If we set the orphanRemoval attribute to the value of false :

And rerun the previous test case, which was calling the removeComment method, Hibernate executed the following SQL statements:

JPA and Hibernate orphanRemoval vs. CascadeType.REMOVE

A very common question is how the orphanRemoval mechanism differs from the CascadeType.REMOVE strategy.

If the orphanRemoval mechanism allows us to trigger a remove operation on the disassociated child entity, the CascadeType.REMOVE strategy propagates the remove operation from the parent to all the child entities.

Therefore, if we execute the following test case:

Hibernate is going to execute three DELETE statements:

First, the child rows are deleted, because if we deleted the post row first, a ConstraintViolationExeption would be triggered since there would be still post_comment rows associated with the post record that was wanted to be deleted.

Don’t use CascadeType.REMOVE with @ManyToMany associations

The CascadeType.REMOVE strategy is useful for the @OneToMany and @OneToOne associations only. If you are using a @ManyToMany association, you should never set the CascadeType.ALL attribute value, as you’ll also inherit the CascadeType.REMOVE strategy.

Cascading makes sense from a parent entity to a child. Because a collection annotated with @ManyToMany associates two parent entities via a join table, we don’t want to propagate the remove from one parent to another. Instead, we want to propagate the remove operation from the parent to the join table child records.

When removing an element from the @ManyToMany collection, Hibernate generates a DELETE statement for the join table record. So, it works like orphanRemoval, but instead of propagating the remove to the actual entity that is removed from the collection, it triggers the DELETE statement for the child row in the join table.

For more details about this topic, check out this article.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

orphanremoval hibernate что это. Смотреть фото orphanremoval hibernate что это. Смотреть картинку orphanremoval hibernate что это. Картинка про orphanremoval hibernate что это. Фото orphanremoval hibernate что это orphanremoval hibernate что это. Смотреть фото orphanremoval hibernate что это. Смотреть картинку orphanremoval hibernate что это. Картинка про orphanremoval hibernate что это. Фото orphanremoval hibernate что это

Conclusion

The orphanRemoval strategy simplifies the child entity state management, as we only have to remove the child entity from the child collection, and the associated child record is deleted as well.

Источник

Как работает orphanRemoval

Рассмотрим настройку orphanRemoval, которая касается удаления элементов из коллекции. У нас это будет удаление комментария из списка комментариев топика.
orphanremoval hibernate что это. Смотреть фото orphanremoval hibernate что это. Смотреть картинку orphanremoval hibernate что это. Картинка про orphanremoval hibernate что это. Фото orphanremoval hibernate что это

Модель

То есть продолжаем работать с теми же таблицами — топик и комментарии в отношении @OneToMany и @ManyToOne:

Обратите внимание на метод removeComment() :

Так данные остаются согласованными. Hibernate автоматически не может обеспечить согласованность двусторонних (bidirectional) отношений, и надо делать это самостоятельно.

orphanRemoval — свойство внутри аннотации @OneToMany (см. выше).

Данные

В базу добавим один топик с тремя комментариями — этого достаточно, чтобы протестировать orphanRemoval.

Чтобы понять смысл настройки orphanRemoval, надо представить, что теоретически может подразумеваться под удалением комментария из списка комментариев топика.

Очевидно это означает, что у данного топика больше нет комментария.

За эти два варианта и отвечает orphanRemoval.

orphanRemoval=true

Если orphanRemoval=true, то при удалении комментария из списка комментариев топика, он удаляется из базы. Проверим это в тесте:

Как видите, тут оператор delete. Он и удаляет комментарий из базы.

orphanRemoval=false

Если orphanRemoval=false, то при удалении комментария из списка, в базе комментарий остается. Просто его внешний ключ (comment.topic_id) обнуляется, и больше комментарий не ссылается на топик.

Здесь происходит обновление таблицы comment: столбцу topic_id присваивается значение NULL. Комментарий остается в базе, просто ни на какой топик он больше не ссылается.

Оператора delete нет.

orphanRemoval vs CascadeType.REMOVE

Иногда путают настройки orphanRemoval и CascadeType.REMOVE. Хотя CascadeType.REMOVE совсем о другом.

Все каскады просто повторяют действие, выполняемое с родительской сущностью: они проделывают его также с дочерними сущностями.

У нас родительская сущность — топик, дочерние сущности — комментарии.

CascadeType.REMOVE говорит о том, что при удалении топика надо также удалять его комментарии из базы.

Пример: удалим топик с id=-1l. У него три комментария, и эти три комментария — всё, что есть в таблице комментариев. Убедимся, что комментарии из базы тоже удаляются:

Здесь последним оператором delete удаляется топик, а первыми тремя — три комментария, которые относятся к этому топику.

Настройка orphanRemoval на исход операции не влияет.

Источник

Глава 11. Работа с объектами

Hibernate — это полное объектно-реляционное решение для отображений, которое не только скрывает от разработчика детали системы управления базами данных, но также предлагает управление состояниями объектов. Это, вместо управления инструкциями SQL на низком уровне, даёт возможность работать с JDBC/SQL на высоком уровне в естественном для Java-приложений объектно-ориентированным стиле.

Другими словами, разработчики приложений Hibernate всегда должны думать о состоянии своих объектов, а не только о выполнении SQL-инструкций.

11.1. Состояния объектов Hibernate

Hibernate определяет и поддерживает следующие состояния объектов:

Рассмотрим более подробно состояния и переход состояний (и методы Hibernate, которые инициируют переход).

11.2. Делаем объекты постоянными (persistent)

Вновь сохданные экземпляры постоянного класса считаются переходными по Hibernate. Мы можем сделать переходный экземпляр постоянным, связав его с сессией:

Обычно вы не беспокоитесь об этой детали, так как обычно используете функцию переходного постоянства (transitive persistence) Hibernate для автоматического сохранения связанных объектов. Тогда даже нарушения ограничений NOT NULL не встретятся — Hibernate позаботится обо всём. Переходное постоянство (Transitive persistence) обсуждается далее в этой главе.

11.3. Загрузка объекта

Методы load() из Session предоставляют способ получения постоянного экземпляра, если вы знаете его идентификатор. load() принимает объект класса и загружает состояние в только что созданный экземпляр этого класса в постоянном состоянии.

Кроме того, вы можете загрузить состояние в данный экземпляр:

Имейте в виду, что load() выдает невосстанавливаемое исключение, если нет соответствующей записи в базе данных. Если класс отображён на прокси, load() просто возвращает неинициализированный прокси и фактически не попадает в базу данных до тех пор, пока вы не вызовете метод прокси. Это полезно, если вы хотите создать связь с объектом, не загружая его из базы данных. Он также позволяет загружать несколько экземпляров в виде пакета, если batch-size определён для отображения классов.

Как много загрузит Hibernate из базы данных и сколько SQL SELECT будут использовано? Это зависит от стратегии выборки (fetching strategy) и объясняется в разделе 20.1 «Стратегии выборки (fetching strategy)».

11.4. Запросы

Если вы не знаете идентификаторы объектов, которые вы ищете, вам нужен запрос. Hibernate поддерживает простой, но мощный объектно-ориентированный язык запросов (HQL). Для создания программных запросов Hibernate поддерживает сложные функциональные возможности: Criteria и Example (QBC и QBE). Вы также можете выразить свой запрос в нативном SQL вашей базы данных, с дополнительной поддержкой Hibernate для преобразования результатов в объекты.

11.4.1. Выполнение запросов

11.4.1.1. Итерирование результатов

11.4.1.2. Запросы, возвращающие кортежи (tuples)

Иногда запросы Hibernate возвращают кортежи объектов. Каждый кортеж возвращается как массив:

11.4.1.3. Скалярные результаты

11.4.1.4. Привязка (bind) параметров

11.4.1.5. Пагинация

Если вам нужно указать границы вашего результирующего набора, то есть максимальное количество записей, которые вы хотите получить, и/или первую запись, которую вы хотите получить, вы можете использовать методы интерфейса Query :

Hibernate знает, как перевести этот ограниченный запрос в нативный SQL вашей СУБД.

11.4.1.6. Прокручиваемая итерация

11.4.1.7. Внешние именованные запросы

Пример 11.1. Определение именованного запроса с помощью @NamedQuery.

Пример 11.2. Определение именованного запроса с помощью

Привязка и выполнение параметров происходит программно, как показано в примере 11.3 «Привязка параметров именованного запроса».

Пример 11.3. Привязка параметров именованного запроса

Фактический программный код не зависит от используемого языка запросов. Вы также можете определить нативные SQL-запросы в метаданных или перенести существующие запросы в Hibernate, поместив их в файлы отображения.

11.4.2. Фильтрация коллекций

Возвращённая коллекция считается сумкой (bag), которая является копией данной коллекции. Оригинальная коллекция не изменяется. Это противоречит импликации имени «filter», но соответствует ожидаемому поведению.

Даже пустой запрос фильтра полезен, например для загрузки подмножества элементов в большой коллекции:

11.4.3. Запросы Criteria

HQL чрезвычайно эффективен, но некоторые разработчики предпочитают строить запросы динамически, используя объектно-ориентированный API. Для этих случаев Hibernate предоставляет интуитивный API запросов Criteria :

API Criteria и связанный с ним Example обсуждаются более подробно в главе 17 «Запросы Criteria».

11.4.4. Запросы на нативном SQL

SQL-запросы могут содержать именованные и позиционные параметры, подобно запросам Hibernate. Более подробную информацию о нативных SQL-запросах в Hibernate можно найти в главе 18. «Нативный SQL».

11.5. Изменение постоянных объектов

Иногда эта модель программирования неэффективна, так как в одной сессии требуется как SQL SELECT для загрузки объекта, так и SQL UPDATE для сохранения его обновлённого состояния. Hibernate предлагает альтернативный подход, используя отсоединённые (detached) экземпляры.

11.6. Изменение отсоединённых (detached) объектов

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

Hibernate поддерживает эту модель, обеспечивая повторное присоединение отсоединённых экземпляров с использованием методов Session.update() или Session.merge() :

Приложение должно индивидуально вызывать update() для отсоединённых экземпляров, которые доступны из данного отсоединёного экземпляра, только если оно хочет, чтобы их состояние было обновлено. Это может быть автоматизировано с использованием переходного постоянства (Transitive persistence). Дополнительную информацию см. в разделе 11.11 «Переходное постоянство (Transitive persistence)».

Метод lock() также позволяет приложению повторно ассоциировать объект с новой сессией. Однако отделённый экземпляр должен быть немодифицирован.

11.7. Автоматическое обнаружение состояния

Пользователи Hibernate запросили метод общего назначения, который либо сохраняет переходный экземпляр, генерируя новый идентификатор, либо обновляет/повторно присоединяет отсоединённый экземпляр, связанный с его текущим идентификатором. Метод saveOrUpdate() реализует этот функционал.

Обычно update() или saveOrUpdate() используются в следующем сценарии:

saveOrUpdate() выполняет следующие действия:

а merge() очень отличается:

11.8. Удаление постоянных объектов

Session.delete() удалит состояние объекта из базы данных. Однако ваше приложение может содержать ссылку на удалённый объект. Лучше думать о delete() как о методе, делающем постоянный экземпляр переходным.

Вы можете удалять объекты в любом порядке, без риска нарушения внешнего ключа. По-прежнему можно нарушить ограничение NOT NULL в столбце внешнего ключа, удалив объекты в неправильном порядке. Например, если вы удалите родителя, но забудьте удалить детей.

11.9. Репликация объекта между двумя разными хранилищами данных

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

ReplicationMode определяет, как replicate() будет иметь дело с конфликтами с существующими записями в базе данных:

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

11.10. Сброс (flush) сессии

Иногда Session выполняет инструкции SQL, необходимые для синхронизации состояния соединения JDBC с состоянием объектов, хранящихся в памяти. Этот процесс, называемый сброс (flush), происходит по умолчанию в следующих точках:

Операторы SQL выдаются в следующем порядке:

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

Во время сброса (flush) может возникнуть исключение (например, если операция DML нарушает ограничение). Поскольку обработка исключений предполагает некоторое понимание поведения транзакционний Hibernate, мы обсуждаем его в главе 13 «Транзакции и параллельное выполнение».

11.11. Переходное постоянство (Transitive persistence)

Довольно обременительно сохранять, удалять или повторно присоединять отсоединённые объекты, особенно если вы имеете дело с графом связанных объектов. Частным случаем является отношение родитель/ребёнок. Рассмотрим следующий пример:

Если детям в отношении родитель/ребёнок будут введены значения (например, набор адресов или строк), их жизненный цикл будет зависеть от родителя, и для удобного «каскадирования» изменений состояния не потребуется никаких дополнительных действий. Когда родитель будет сохранён, дочерние объекты с типом значений (value-typed) сохраняются, а когда родитель будет удалён, дети будут удалены и т.д. Это работает для таких операций, как удаление дочернего объекта из коллекции. Поскольку объекты с типом значений (value-typed) не могут иметь общие ссылки, Hibernate обнаружит это и удалит дочерний объект из базы данных.

Теперь рассмотрим один и тот же сценарий с родительскими и дочерними объектами, являющимися сущностями, а не типами значений (например, категориями и объектами, или родительскими и дочерними кошками). У сущностей есть свой жизненный цикл и поддержка общих ссылок. Удаление сущности из коллекции не означает, что она может быть удалена), и по умолчанию нет каскадирования состояния от одной сущности к любым другим связанным сущностям. Hibernate по умолчанию не реализует постоянство по повторному присоединению.

Каскадные стили можно сочетать:

Если вы используете аннотации, вы, вероятно, заметили, что атрибут cascade принимает массив CascadeType в качестве значения. Каскадная концепция в JPA очень похожа на переходное постоянство (transitive persistence) и каскадирование операций, как описано выше, но с немного отличающейся семантикой и каскадированием типов:

Заметка

Пример 11.4. @OneToMany с orphanRemoval

Отображение ассоциации (либо однозначной ассоциации, либо коллекции) с cascade=«all» помечает ассоциацию как отношение в стиле родитель/ребёнок, где сохранение, обновление или удаление родительского объекта приводит к сохранению, обновлению или удалению дочернего объектов.

Наконец, обратите внимание, что каскадирование операций может быть применено к графу объектов во время вызова или во время сборса. Все операции, если они включены, каскадируются на ассоциированные сущности, доступные при выполнении операции. Однако save-update и delete-orphan являются транзитивными для всех ассоциированных сущностей, доступных во время сессии.

11.12. Использование метаданных

Hibernate требует богатой метауровневой модели всех типов сущностей и значений. Эта модель может быть полезна для самого приложения. Например, приложение может использовать метаданные Hibernate для реализации «умного» алгоритма «глубокого копирования», который понимает, какие объекты следует копировать (например, изменяемые типы значений) и какие нет (например, неизменные типы значений и, возможно, ассоциированные объекты).

Источник

Как orphanRemoval работает с JPA и гибернацией

Узнайте, как работает механизм orphanRemoval при использовании JPA и Hibernate и как он запускает операцию удаления дочернего элемента, когда дочерний элемент отключен.

Вступление

В этой статье мы рассмотрим, как механизм JPA и Hibernate orphanRemoval позволяет нам запускать операцию дочернего объекта удалить при отсоединении ссылки на дочернюю сущность от дочерней коллекции на родительской стороне.

Модель предметной области

Мы собираемся использовать Сообщение и Комментарий к сообщению сущность, которая образует отношение таблицы “один ко многим” :

@ManyToOne аннотация в Комментарии к сообщению сущности отображает столбец post_id внешнего ключа, который образует отношение таблицы “один ко многим” между родительской публикацией и post_comment дочерними таблицами:

И объект Post отображается следующим образом:

Атрибут orphanRemoval даст указание поставщику JPA инициировать переход в состояние удаления сущности, когда PostComment сущность больше не ссылается на свою родительскую Post сущность.

Поскольку у нас есть двунаправленная связь “один ко многим”, нам нужно убедиться, что обе стороны связи синхронизированы, и по этой причине мы создали методы AddComment и removeComment для синхронизации обоих концов при добавлении или удалении новой дочерней сущности. Ознакомьтесь с этой статьей для получения более подробной информации.

JPA и каскадный тип спящего режима.Механизм СОХРАНЕНИЯ

Давайте создадим Сообщение сущность с двумя Комментарием к сообщению дочерними сущностями:

JPA и механизм временного отключения в спящем режиме

Если мы загрузим Сообщение сущность вместе с ее двумя последующими дочерними сущностями и удалим первый Комментарий к сообщению :

Hibernate выполнит следующие инструкции SQL:

Если мы установим для атрибута orphanRemoval значение false :

JPA и гибернация сиротского времени по сравнению с каскадным типом.УДАЛИТЬ

Если механизм orphanRemoval позволяет нам запустить операцию удаления для несвязанной дочерней сущности, стратегия CascadeType.REMOVE распространяет операцию удаления от родительской сущности на все дочерние сущности.

Поэтому, если мы выполним следующий тестовый случай:

Hibernate выполнит три инструкции УДАЛЕНИЯ:

Не используйте CascadeType.УДАЛИТЕ с помощью @ManyToMany ассоциаций

При удалении элемента из коллекции @ManyToMany Hibernate создает инструкцию DELETE для записи таблицы объединения. Таким образом, он работает как orphanRemoval, но вместо распространения удаления на фактическую сущность, удаляемую из коллекции, он запускает инструкцию DELETE для дочерней строки в таблице объединения.

Вывод

Стратегия orphanRemoval упрощает управление состоянием дочерней сущности, так как нам нужно только удалить дочернюю сущность из дочерней коллекции, и связанная дочерняя запись также удаляется.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *