Що таке orphan removal
Orphan removal — механізм автоматичного видалення пов'язаних сутностей, коли вони видаляються з колекції або зв'язок з ними розривається. Це потужний інструмент для підтримки ці...
Огляд
Orphan removal — механізм автоматичного видалення пов’язаних сутностей, коли вони видаляються з колекції або зв’язок з ними розривається. Це потужний інструмент для підтримки цілісності даних в композиціях.
🟢 Junior Level
Що таке orphan removal
Orphan removal — автоматично видаляє пов’язані сутності з БД, коли вони видаляються з колекції.
@Entity
public class Order {
@OneToMany(mappedBy = "order", orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
}
Order order = entityManager.find(Order.class, 1L);
order.getItems().remove(0); // видалений item автоматично видалиться з БД!
Cascade vs orphanRemoval
// Cascade — propagates операції
@OneToMany(cascade = CascadeType.REMOVE)
// entityManager.remove(order) → remove для всіх items
// orphanRemoval — видаляє orphan entities
@OneToMany(orphanRemoval = true)
// order.getItems().remove(item) → DELETE для item з БД
// Разом — повний контроль
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
// persist, merge, remove + automatic orphan deletion
🟡 Middle Level
Cascade + orphanRemoval разом
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items;
order.getItems().add(newItem); // persist через cascade
order.getItems().remove(oldItem); // delete через orphanRemoval
order.getItems().clear(); // delete ALL через orphanRemoval
Коли orphanRemoval працює
✅ @OneToMany
✅ @OneToOne
❌ @ManyToOne — немає сенсу
❌ @ManyToMany — немає сенсу
Типові помилки
// ❌ orphanRemoval для shared entities
@ManyToOne(orphanRemoval = true) // ❌ не можна для @ManyToOne
private User user;
// ❌ orphanRemoval для @ManyToMany
@ManyToMany(orphanRemoval = true) // ❌ не можна для @ManyToMany
private List<Tag> tags;
🔴 Senior Level
Внутрішня реалізація
orphanRemoval mechanism:
1. При flush: Hibernate перевіряє всі колекції з orphanRemoval
2. Порівнює поточний стан з snapshot
3. Entities які були в snapshot, але немає в поточному → orphan
4. Для кожного orphan → schedule DELETE
5. При flush → DELETE з БД
Важливо: orphanRemoval спрацьовує при flush, не одразу!
Production патерни
// Pattern 1: Helper method
@Entity
public class Order {
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
public void addItem(OrderItem item) {
items.add(item);
item.setOrder(this);
}
public void removeItem(OrderItem item) {
items.remove(item);
item.setOrder(null); // важливо для консистентності
}
}
Best Practices
✅ orphanRemoval для composite children
✅ З cascade = ALL
✅ Helper methods для модифікації колекції
✅ Тільки для private ownership
❌ Для shared entities
❌ Без cascade
❌ Для @ManyToOne або @ManyToMany
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- orphanRemoval — автоматично видаляє з БД сутності видалені з колекції
- Cascade.REMOVE — тільки при видаленні батька, orphanRemoval — при видаленні з колекції
- Працює тільки для @OneToMany та @OneToOne, НЕ для @ManyToOne/@ManyToMany
- Спрацьовує при flush, не одразу — важливо для розуміння таймінгу
Пов’язані теми:
- [[20. Як працюють каскадні операції (Cascade)]]
- [[21. Які типи Cascade існують]]
- [[23. Як правильно використовувати @OneToMany і @ManyToOne]]
- [[24. У чому особливості bidirectional relationships]]