Question 21 · Section 16

What Cascade Types Exist

JPA provides several cascade operation types, each controlling the propagation of a specific operation type to related entities. Choosing the right cascade type is key to correc...

Language versions: English Russian Ukrainian

Overview

JPA provides several cascade operation types, each controlling the propagation of a specific operation type to related entities. Choosing the right cascade type is key to correctly working with object graphs.


Junior Level

All CascadeType Types

CascadeType.ALL       - all operations (persist, merge, remove, refresh, detach)
CascadeType.PERSIST   - on persist(parent) -> persist(child)
CascadeType.MERGE     - on merge(parent) -> merge(child)
CascadeType.REMOVE    - on remove(parent) -> remove(child)
CascadeType.REFRESH   - on refresh(parent) -> refresh(child)
CascadeType.DETACH    - on detach(parent) -> detach(child)

Example of Each

// PERSIST - saving with children
@OneToMany(cascade = CascadeType.PERSIST)
private List<OrderItem> items;

entityManager.persist(order);  // -> persist for all items

// MERGE - updating with children
@OneToMany(cascade = CascadeType.MERGE)
private List<OrderItem> items;

entityManager.merge(order);  // -> merge for all items

// REMOVE - deleting with children
@OneToMany(cascade = CascadeType.REMOVE)
private List<OrderItem> items;

entityManager.remove(order);  // -> remove for all items

// ALL - all operations
@OneToMany(cascade = CascadeType.ALL)
private List<OrderItem> items;

When NOT to Use Cascade at All

Don’t use cascade when both entities are aggregate roots with their own lifecycle. For example, Order and Customer are separate aggregates, cascading between them is dangerous.

Middle Level

When to Use What

@OneToMany (composite):  CascadeType.ALL + orphanRemoval = true
@ManyToOne:              CascadeType.PERSIST, MERGE (or no cascade)
@OneToOne:               CascadeType.ALL
@ManyToMany:             CascadeType.PERSIST, MERGE

Composite vs Association

// Composite - child doesn't exist without parent
@Entity
public class Order {
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderItem> items;  // OrderItem without Order has no meaning
}

// Association - entities are independent
@Entity
public class Order {
    @ManyToOne  // no cascade
    private User user;  // User exists independently of Order
}

Common Mistakes

// Cascade.REMOVE for shared entities
@ManyToOne(cascade = CascadeType.REMOVE)
private User user;

entityManager.remove(order);  // User also deleted!

// Cascade.ALL for @ManyToOne
@ManyToOne(cascade = CascadeType.ALL)
private Category category;

entityManager.remove(product);  // Category deleted!

// Without cascade for shared
@ManyToOne
private User user;  // User managed separately

Senior Level

Advanced Scenarios

// Scenario 1: Cascade PERSIST + MERGE for @ManyToOne
@Entity
public class Order {
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    // Code smell: cascading from Order to User - shared entity.
    // May accidentally create duplicate users.
    // Cascading PERSIST/MERGE from child to parent is an antipattern.
    private User user;
}

// New User will be saved with Order
User newUser = new User();
Order order = new Order();
order.setUser(newUser);
entityManager.persist(order);  // -> persist User, persist Order

// Existing User will be merged
order.setUser(existingUser);
entityManager.merge(order);  // -> merge User, merge Order

Cascading and Validation

@Entity
public class Order {
    @Valid  // Bean Validation cascade. @Valid is Hibernate Validator (Hibernate-specific), not JPA standard. Validation fires on persist/merge.
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> items;
}

// On persist/merge - validation for all items
entityManager.persist(order);  // -> validation for Order + all items

Production Patterns

// Pattern 1: Order -> OrderItem (composite)
@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);
    }
}

// Pattern 2: Order -> User (shared)
@Entity
public class Order {
    @ManyToOne  // no cascade
    private User user;
}

// Pattern 3: User -> Address (composite)
@Entity
public class User {
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Address> addresses = new ArrayList<>();
}

Decision Matrix

Association Cascade orphanRemoval Why
@OneToMany (composite) ALL true Child doesn’t exist without parent
@ManyToOne (shared) PERSIST, MERGE false Entity managed separately
@OneToOne (composite) ALL true One-to-one, composition
@ManyToMany PERSIST, MERGE false Shared entities, dangerous to delete

Best Practices

ALL for composite children
PERSIST, MERGE for shared entities
Without REMOVE for shared entities
orphanRemoval for composite children
Decision matrix for each association

REMOVE for shared entities
ALL for @ManyToOne
Cascade.REMOVE in Many-to-Many
Without understanding composite/association difference

Interview Cheat Sheet

Must know:

  • 6 CascadeType types: ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH
  • ALL - all operations, but dangerous for @ManyToOne and Many-to-Many
  • Compositions (Order -> OrderItem): CascadeType.ALL + orphanRemoval = true
  • Associations (Order -> User): PERSIST, MERGE or no cascade
  • @ManyToOne with cascade PERSIST/MERGE from child to parent - antipattern (duplicates)
  • Decision matrix: each association gets its own cascade, not universal

Frequent follow-up questions:

  • Why is @ManyToOne with cascade a code smell? Cascading from Order to User may create duplicate users
  • What is composite vs association? Composite - child doesn’t exist without parent (OrderItem), association - independent entities (User)
  • Can cascade types be combined? Yes: cascade = {CascadeType.PERSIST, CascadeType.MERGE}
  • When is cascade not needed at all? When entities are managed separately via their own repositories

Red flags (DO NOT say):

  • “CascadeType.ALL for all associations” - REMOVE deletes shared entities
  • “Cascade.REMOVE for @ManyToOne” - deleting Order deletes User
  • “Cascade.ALL for Many-to-Many” - deleting Author deletes all Books
  • “I don’t understand composite/association difference” - critical for cascade choice

Related topics:

  • [[20. How Do Cascade Operations Work]]
  • [[22. What is Orphan Removal]]
  • [[23. How to Properly Use @OneToMany and @ManyToOne]]
  • [[24. What Are the Peculiarities of Bidirectional Relationships]]