# Cascades, Orphan Removal and Entity Equality — Hibernate / JPA

Source: https://www.skillbyai.com/en/hibernate-jpa/r-cascade

> Use cascade types and orphanRemoval correctly and implement equals and hashCode for entities.

## Propagating operations safely

**Cascading** propagates operations from a parent to related entities: with `cascade = CascadeType.PERSIST`, persisting an order also persists its new lines; `MERGE`, `REMOVE`, `REFRESH`, `DETACH` and `ALL` work similarly. Cascade along **composition** relationships, where children belong to the parent (order → order lines), and **not** along associations between independent aggregates (order → customer): cascading `REMOVE` from an order to its customer would delete the customer. **`orphanRemoval = true`** deletes a child when it is removed from the parent's collection, again appropriate only for owned children. Entities need careful **`equals`/`hashCode`**: identity-based equality works within one persistence context, but entities in `HashSet`s across states need stable hashing. Common safe approaches: base equality on a **natural or business key** that never changes, or on the **ID with a constant hashCode** (so the hash does not change when a new entity receives its ID at persist). Never base equality on all fields, and avoid Lombok `@Data` on entities, which generates field-based equals and `toString` methods that can trigger lazy loading or infinite recursion.

## Cascade within an aggregate and safe equality

Lines cascade from their order; the customer does not.

```java
@Entity
public class PurchaseOrder {
    @Id @GeneratedValue private Long id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)      // independent aggregate: NO cascade
    private Customer customer;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderLine> lines = new ArrayList<>();           // owned children: cascade + orphans

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof PurchaseOrder other)) return false;
        return id != null && id.equals(other.id);               // transient entities are only equal to themselves
    }

    @Override
    public int hashCode() {
        return PurchaseOrder.class.hashCode();                  // constant: stable across persist
    }
}
```

## Cascade REMOVE on many-to-many is dangerous

Cascading REMOVE from an article to its tags deletes the tags for every other article too. Cascade only into entities that cannot exist without the parent.

**Quiz:** Where is CascadeType.ALL with orphanRemoval appropriate?

- [x] From an order to its order lines, which belong only to that order
- [ ] From an order to its customer
- [ ] From any entity to every related entity
- [ ] On every @ManyToMany

*Answer:* From an order to its order lines, which belong only to that order. Cascade and orphan removal suit owned children in a composition, not independent entities.
