Cascade Types

What Cascading Means

Without cascading, every entity must be saved on its own: save the order, then save each item. Cascading tells Hibernate: "when I do operation X on the parent, do X on these children too".

CascadeTypeParent operation passed to children
PERSISTpersist() / save() of a new parent saves new children
MERGEmerge() of a detached parent merges the children
REMOVEdeleting the parent deletes the children
REFRESHreloading the parent from the DB reloads the children
DETACHdetaching the parent detaches the children
ALLall of the above

Cascade from Order to Items

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
Order order = new Order(user);
order.addItem(new OrderItem(phoneCase, 1, new BigDecimal("299")));
order.addItem(new OrderItem(charger, 2, new BigDecimal("749")));
orderRepository.save(order);      // one call saves the order AND both items

Generated SQL

orderRepository.save(order);

Example output

DEBUG org.hibernate.SQL : insert into orders (status,total,user_id) values (?,?,?)
DEBUG org.hibernate.SQL : insert into order_items (order_id,price,product_id,quantity) values (?,?,?,?)
DEBUG org.hibernate.SQL : insert into order_items (order_id,price,product_id,quantity) values (?,?,?,?)

Where Cascading Belongs

Cascade from a parent to children it owns (whose life depends on the parent). Never cascade towards shared, independent entities.

AssociationCascade?Why
Order.itemsALL + orphanRemovalan item cannot exist without its order
OrderItem.productnonedeleting an order must not delete the product
Product.categorynonemany products share one category
User.wishlist (ManyToMany)never REMOVEit would delete products other users wishlisted

Note: CascadeType.REMOVE on a @ManyToOne or @ManyToMany is almost always a bug. Deleting one order item could delete the product, and with it every other order's reference fails.

Practice

Exercise: A Product has a list of ProductImage rows (URLs of photos). Images are uploaded with the product and deleted with it. Write the mapping on Product.

Show answer
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
@OrderColumn(name = "position")          // optional: keep the photo order
private List<ProductImage> images = new ArrayList<>();

public void addImage(ProductImage img) { images.add(img); img.setProduct(this); }
public void removeImage(ProductImage img) { images.remove(img); img.setProduct(null); }