✅ Short Answer
Orphan removal means that if you remove a child entity from its parent’s collection, JPA will automatically delete that child entity from the database, treating it as an “orphan.”
🔎 Detailed Explanation
🔹 By default in a @OneToMany
or @OneToOne
relationship, if you remove a child from the parent’s collection, the child’s foreign key is set to NULL
(if nullable) but the child row stays in the database.
🔹 With orphanRemoval = true
, removing the child from the parent’s collection instructs Hibernate/JPA to delete the child entity entirely.
🔹 This helps ensure your object model stays in sync with the database → children not attached to any parent don’t hang around as “orphans.”
🧑💻 Example
@Entity
public class ParentEntity {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ChildEntity> children = new ArrayList<>();
}
@Entity
public class ChildEntity {
@Id @GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "parent_id")
private ParentEntity parent;
}
✅ Here, orphanRemoval=true
on the parent’s @OneToMany
.
Code using orphan removal:
// Load parent with 2 children
ParentEntity parent = session.find(ParentEntity.class, 1L);
ChildEntity child = parent.getChildren().get(0);
// Remove child from parent's collection
parent.getChildren().remove(child);
SQL generated with orphan removal:
delete from child_entity where id=child.id;
✅ The child is deleted from the database automatically when removed from the parent’s collection.
🔹 Without orphanRemoval
If orphanRemoval=false
, the same code would just set the child’s parent_id
to NULL
(if allowed), leaving the row in the child table.
📌 Key Takeaways
✅ orphanRemoval=true
→ deleting from parent collection deletes child from DB.
✅ Ensures no “orphan” child rows remain → great for enforcing aggregate boundaries.
✅ Often used together with cascade=CascadeType.ALL
for full lifecycle control of child entities.
if i write parent.getChildren().remove(child);
when it will be removed ?
✅ Short Answer
When you call parent.getChildren().remove(child)
, the child won’t be deleted immediately.
Instead, Hibernate schedules the delete operation to happen on the next flush — which usually occurs:
✅ Automatically at transaction commit,
✅ Or when you explicitly call entityManager.flush()
or session.flush()
.
🔎 Detailed Explanation
🔹 JPA/Hibernate works with a persistence context, where entity changes are tracked but not instantly applied to the database.
🔹 So, when you do:
parent.getChildren().remove(child);
- Hibernate marks the child for deletion (because of
orphanRemoval=true
). - The actual
DELETE
SQL won’t execute immediately.
🔹 When does it execute?
1️⃣ On flush: either explicit entityManager.flush()
/ session.flush()
, or
2️⃣ On transaction commit: when you call transaction.commit()
, Hibernate automatically flushes pending changes.
🔹 Example Timeline
transaction.begin();
ParentEntity parent = em.find(ParentEntity.class, 1L);
ChildEntity child = parent.getChildren().get(0);
parent.getChildren().remove(child); // schedules delete
// Still no DELETE SQL yet!
transaction.commit(); // triggers flush → Hibernate issues DELETE SQL:
// delete from child_entity where id=...
🔹 Important Notes
✅ If you rollback the transaction before commit, the pending delete is discarded → the child is not removed from the database.
✅ Hibernate batches these pending operations for efficiency.
📌 Key Takeaways
✅ Removing a child from the collection with orphanRemoval=true
schedules the child for deletion.
✅ The delete happens when the persistence context flushes, typically at transaction commit.
✅ Understanding this helps avoid surprises (e.g., seeing data still present before commit).