JPA / Hibernate Cascade Types - CascadeType.MERGE

In this post, we will discuss the usage of JPA CascadeType.MERGE with an example.

Cascading is the way to achieve this. When we perform some action on the target entity, the same action will be applied to the associated entity.

JPA Cascade Types:

All JPA-specific cascade operations are represented by the javax.persistence.CascadeType enum containing entries:

  • ALL - cascades all entity state transitions
  • PERSIST - cascades the entity persist operation.
  • MERGE - cascades the entity merge operation.
  • REMOVE - cascades the entity to remove operation.
  • REFRESH - cascades the entity refresh operation.
  • DETACH - cascades the entity detach operation.

Hibernate Cascade Types:

Hibernate supports three additional Cascade Types along with those specified by JPA. These Hibernate-specific Cascade Types are available in org.hibernate.annotations.CascadeType:
  • SAVE_UPDATE - cascades the entity saveOrUpdate operation.
  • REPLICATE - cascades the entity replicate operation.
  • LOCK - cascades the entity lock operation.

JPA / Hibernate Cascade Types - CascadeType.MERGE

The merge operation copies the state of the given object onto the persistent object with the same identifier. CascadeType.MERGE propagates the merge operation from a parent to a child entity.

Consider we have Person and Address JPA entities:

Person.java

@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;
    // getters and setters
}

Address.java

@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;
   
    // getter and setter methods
}

Using CascadeType.MERGE

The merge operation copies the state of the given object onto the persistent object with the same identifier. CascadeType.MERGE propagates the merge operation from a parent to a child entity.

Let's test the merge operation:

Person person = new Person();
person.setName("Admin");

Address address = new Address();
address.setCity("Mumbai");
address.setHouseNumber(23);
address.setStreet("Rural");
address.setZipCode(123456);
address.setPerson(person);

person.setAddresses(Arrays.asList(address));
session.persist(person);
session.flush();
addressId = address.getId();
session.clear();

Address savedAddressEntity = session.find(Address.class, addressId);
Person savedPersonEntity = savedAddressEntity.getPerson();
savedPersonEntity.setName("Administrator");
savedAddressEntity.setHouseNumber(24);
session.merge(savedPersonEntity);
session.flush();

When we run the above test case, the merge operation generates the following SQL:

Hibernate: select address0_.id as id1_0_0_, address0_.city as city2_0_0_, address0_.houseNumber as houseNum3_0_0_, address0_.person_id as person_i6_0_0_, address0_.street as street4_0_0_, address0_.zipCode as zipCode5_0_0_ from Address address0_ where address0_.id=?
Hibernate: select person0_.id as id1_1_0_, person0_.name as name2_1_0_ from Person person0_ where person0_.id=?
Hibernate: update Address set city=?, houseNumber=?, person_id=?, street=?, zipCode=? where id=?
Hibernate: update Person set name=? where id=?

Here, we can see that the merge operation first loads both address and person entities and then updates both as a result of CascadeType MERGE.

References



Comments