Удаление дочерней записи в JPA OneToMany: возможные решения
Быстрый ответ
Для правильного удаления дочерних сущностей в связи @OneToMany
JPA рекомендуется использовать orphanRemoval = true
совместно с CascadeType.REMOVE
или CascadeType.ALL
. Не забудьте исключить дочерний элемент из коллекции родительской сущности.
@Entity
public class Parent {
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Child> children;
public void removeChild(Child child) {
children.remove(child);
child.setParent(null);
}
}
Чтобы инициировать процесс удаления, достаточно вызвать метод parent.removeChild(childEntity)
в контексте транзакции.
Вопросы каскадного удаления
Работа с взаимосвязями между объектами в мире JPA часто напоминает искусство кулинара, готовящего блюдо: каждое действие — проработанное и уместное. Это относится и к вопросам композиции и агрегации. Композиция предполагает, что существование дочерних элементов невозможно без родительского, и часто влечёт за собой каскадное удаление.
Настройка @OneToMany
для каскадного удаления
Необходимость индивидуальной настройки связей:
- Включите
orphanRemoval = true
, чтобы JPA автоматически удаляла "сирот". - Настройте связь между
@OneToMany
и@ManyToOne
для эффективного управления отношениями в JPA. - Используйте
CascadeType.PERSIST
,CascadeType.MERGE
илиCascadeType.DELETE
для детального контроля над проводимыми операциями.CascadeType.ALL
удобен, но может привести к нежелательной потере данных.
Преимущества используемых JPA провайдеров
Воспользуйтесь особенностями выбранного вами JPA провайдера:
- Hibernate предлагает аннотацию
@org.hibernate.annotations.OnDelete
со стратегиейOnDeleteAction.CASCADE
и дополнительную возможность —cascade="delete-orphan"
. - EclipseLink предоставляет функцию "private ownership", ведущую себя похожим образом на каскадное удаление.
Визуализация
Представим дерево с листьями; каждый лист — это сущность JPA, которая стремится остаться на дереве.
🌳 До удаления: 🌳 После удаления:
/ | \ / | \
🍃 🍃 🍃 🍃 🍃 🍂 🍃
На втором изображении видно, как одна из сущностей была удалена вместе с родительской сущностью.
Чтобы поддерживать порядок:
- Включите
orphanRemoval = true
иCascadeType.REMOVE
. - Позвольте JPA поддерживать целостность вашей базы данных, как дерево поддерживает баланс в природе.
Рекомендации по удалению данных
Советы по удалению:
- Тщательно проводите тестирование процесса удаления при помощи Ajax. Отладьте этот процесс до автоматизма.
- Помните, что только при использовании
orphanRemoval
возможно удалить сущность без родительской связи. - Удостоверьтесь, что ваша версия Hibernate поддерживает удаление "сирот" (начиная с версии
3.5.0-Beta-2
). - Разберитесь, как операции JPA отражаются на уровне базы данных.
Для размышления
- Подумайте, действительно ли вам нужен
orphanRemoval
. Возможно, он может принести больше проблем. - Используйте
CascadeType.ALL
с осторожностью, чтобы не утратить важные данные. - Правильно определите границы транзакций. Это поможет вам грамотно управлять взаимоотношениями.
Полезные материалы
- Java Persistence/OneToMany – Wikibooks — Обстоятельное руководство по использованию
@OneToMany
в JPA. - Руководство пользователя Hibernate ORM — Более глубокая информация по ассоциациям от Hibernate.
- java – CascadeType.ALL в JPA и Hibernate – Stack Overflow — Обсуждение значения и последствий использования CascadeType в JPA и Hibernate.
- JSR-000338 Java Persistence 2.1 — Официальный документ, определяющий спецификации JPA 2.1.
- java – JPA OneToMany не удаляет дочерний элемент – Stack Overflow — Обсуждение проблемы каскадного удаления в JPA.
- Сущности – Учебник Java EE 6 — Компактное руководство по управлению сущностями в Java EE 6.
- Кэширование второго уровня в Hibernate – Vlad Mihalcea — Анализ работы кэширования второго уровня в Hibernate от Влада Михалчи.