hibernate Cascade

hibernate Cascade

https://www.baeldung.com/jpa-cascade-types

Entity relationships often depend on the existence of another entity — for example, the PersonAddress relationship. Without the Person, the Address entity doesn't have any meaning of its own. When we delete the Person entity, our Address entity should also get deleted.

  • ALL
  • PERSIST
  • MERGE
  • REMOVE
  • REFRESH
  • DETACH

Eg: person has multiple address

@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
private List<Address> addresses;
}

@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String street;
private int houseNumber;
private String city;
private int zipCode;
@ManyToOne(fetch = FetchType.LAZY)
private Person person;
}

CascadeType.REMOVE

*ascadeType.REMOVE* propagates the remove operation from parent to child entity. Similar to JPA's *CascadeType.REMOVE,* we have *CascadeType.DELETE*, which is specific to Hibernate.

@Test
public void whenParentRemovedThenChildRemoved() {
int personId;
Person person = buildPerson("devender");
Address address = buildAddress(person);
person.setAddresses(Arrays.asList(address));
session.persist(person);
session.flush();
personId = person.getId();
session.clear();

Person savedPersonEntity = session.find(Person.class, personId);
session.remove(savedPersonEntity);
session.flush();
}

When we run the above test case, we'll see the following SQL:

Hibernate: delete from Address where id=?
Hibernate: delete from Person where id=?

Think twice before using Cascade Delete

@Entity
public class PurchaseOrder {

@OneToMany(mappedBy = "order", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Item> items = new ArrayList<Item>();

...
}

Hibernate needs to select all associated Item entities and remove them one by one.

Solution:

em.flush();
em.clear();

Query q = em.createQuery("DELETE Item i WHERE i.order.id = :orderId");
q.setParameter("orderId", orderId);
q.executeUpdate();

order = em.find(PurchaseOrder.class, orderId);
em.remove(order);

ou first need to call the flush() method on the EntityManager to make sure that Hibernate wrote all changes to the database. Then you can call the clear() method to detach all entities from the current persistence context and to remove them from the first level cache.

After that is done, you can use a simple JPQL query to remove all associated Item entities before you read and remove the PurchaseOrder entity.

The complexity of this approach is a lot higher than using a simple cascade delete. But as you can see in the following log output, it only needs 3 queries to remove a PurchaseOrder with all associated Item entities.