Home/Learn/Hibernate & JPA/Cascade Types

Cascade Types

Intermediate
Relationships

CascadeType.ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH propagate operations from parent to child; avoid CascadeType.REMOVE on large collections — use bulk queries instead.

Overview

Cascade types determine which `EntityManager` operations on a parent entity are automatically propagated to associated child entities. Without cascading, you must explicitly `persist`, `merge`, or `remove` each child. JPA defines six cascade types: `PERSIST`, `MERGE`, `REMOVE`, `REFRESH`, `DETACH`, and the convenience `ALL` (all six). A common pattern is `cascade = {PERSIST, MERGE}` (equivalently `cascade = ALL` minus `REMOVE`) for owned children where you want lifecycle management but controlled deletion. `orphanRemoval = true` is separate from `CascadeType.REMOVE` and removes children that are no longer referenced in the parent's collection.

The Six Cascade Types

Each type mirrors an `EntityManager` method. `PERSIST` is the most common: saving a new `Order` automatically persists its `OrderItem` children. `MERGE` propagates re-attaching detached graphs. `REMOVE` deletes children when the parent is deleted — dangerous on large collections because Hibernate loads all children first. `REFRESH` and `DETACH` are rarely needed explicitly.

JPA — PERSIST + MERGE cascade with orphanRemoval
@Entity
public class Order {
    @Id @GeneratedValue Long id;

    // PERSIST + MERGE: propagate save/update; NOT remove
    @OneToMany(mappedBy = "order",
               cascade = {CascadeType.PERSIST, CascadeType.MERGE},
               orphanRemoval = true)
    List<OrderItem> items = new ArrayList<>();
}

// em.persist(order) → also persists all items in the list
Order order = new Order();
order.getItems().add(new OrderItem(order, "SKU-1", 2));
em.persist(order);   // items saved automatically

// Remove a single item from the collection
order.getItems().removeIf(i -> i.getSku().equals("SKU-1"));
// orphanRemoval=true → Hibernate fires DELETE for that item on flush

CascadeType.REMOVE vs orphanRemoval

`CascadeType.REMOVE` triggers when you call `em.remove(parent)` — it deletes the parent and all its children. `orphanRemoval = true` triggers when a child is removed from the parent's collection (even without deleting the parent). They can be used together or separately. Neither should be used on large collections — Hibernate loads all children into memory before deleting them.

JPA — REMOVE vs orphanRemoval vs bulk delete
// CascadeType.REMOVE — parent deletion cascades to children
@OneToMany(cascade = CascadeType.REMOVE)
List<Comment> comments;

em.remove(post);
// Hibernate: SELECT * FROM comment WHERE post_id = ?  ← loads ALL comments!
// Then: DELETE FROM comment WHERE id = ?  (one per comment)
// Then: DELETE FROM post WHERE id = ?

// --- orphanRemoval example ---
@OneToMany(orphanRemoval = true)
List<Address> addresses;

// Remove from collection → child deleted even though parent stays
user.getAddresses().remove(oldAddress);
em.flush(); // DELETE FROM address WHERE id = ?

// --- AVOID on large collections: use bulk delete instead ---
em.createQuery("DELETE FROM Comment c WHERE c.post.id = :postId")
  .setParameter("postId", post.getId())
  .executeUpdate();
em.remove(em.getReference(Post.class, post.getId()));

CascadeType.ALL — Convenience and Pitfalls

`CascadeType.ALL` is shorthand for all six types combined. It is appropriate for **owned, dependent** relationships (like `Order → OrderItem`) where the child has no meaning outside the parent. It is **dangerous** for shared entities — cascading REMOVE on a `@ManyToMany` or a shared reference will delete entities that other parents still reference. Always be explicit about which types you need.

JPA — when to use ALL vs explicit types
// GOOD: Order owns its items — ALL is safe
@OneToMany(mappedBy = "order",
           cascade = CascadeType.ALL, orphanRemoval = true)
List<OrderItem> items;

// DANGEROUS: Tags are shared — CascadeType.ALL would delete the Tag
//            from the database when you remove it from a Post's collection
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) // NOT ALL
Set<Tag> tags;

// Rule of thumb:
// Owned, private children   → cascade = ALL, orphanRemoval = true
// Shared/referenced entities → cascade = PERSIST, MERGE only
// Large collections          → skip cascade REMOVE; use bulk queries

Key Points to Remember

  • 1Six cascade types: PERSIST, MERGE, REMOVE, REFRESH, DETACH, ALL (shorthand)
  • 2CascadeType.REMOVE loads all children into memory before deleting — avoid on large collections
  • 3orphanRemoval removes a child when it's dereferenced from the parent's collection
  • 4CascadeType.ALL is safe for private, owned children (OrderItem) but dangerous for shared entities (Tag)
  • 5Use PERSIST + MERGE for most parent-child relationships; add orphanRemoval separately if needed
  • 6For large collection deletes, always prefer a bulk JPQL/SQL DELETE over cascaded removes

Interview Questions

Sign in to ask Aria
1

What is the difference between CascadeType.REMOVE and orphanRemoval=true?

MediumInfosys
2

Why should you avoid CascadeType.REMOVE on a collection with thousands of children?

MediumThoughtWorks
3

When would you use CascadeType.ALL and when is it dangerous?

MediumOracle
4

Can you use orphanRemoval=true on a @ManyToMany relationship?

HardAtlassian
5

What happens if you persist a parent with a new child but forget to add the cascade type?

EasyWipro

Ask Aria about Cascade Types

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…