JPA Cascade Types

Posted By : Simran Ahuja | 04-Mar-2021

What Is Cascading?

 

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

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

 

2.1. JPA Cascade Type

 

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

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

 

Difference Between the Cascade Types

 

CascadeType.ALL

 

Cascade.ALL propagate all of the operations — including Hibernate-specific ones — from a parent to a child entity.

Let's see it in an example:

@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;
}

 

Note that in OneToMany associations, we've to mention cascade type in the annotation.

 

Now, let's see the associated entity Address:

@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;
}

 

Also Read: Reading a csv file in java

 

CascadeType.PERSIST

 

The persist operation is used to make a transient instance persistent. CascadeType PERSIST propagates the Persist operation from a parent to the following child entity. When we save the person entity, the address entity will also be saved.

Let's see the following test case for a Persist operation:

@Test
public void whenParentSavedThenChildSaved() {
    Person person = new Person();
    Address address = new Address();
    address.setPerson(person);
    person.setAddresses(Arrays.asList(address));
    session.persist(person);
    session.flush();
    session.clear();
}

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

Hibernate: insert into Person (id, name) values (?, ?)
Hibernate: insert into Address (
    city, houseNumber, person_id, street,id) values (?, ?, ?, ?,?)

 

3.3. 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 the following child entity.

Let's test the merge operation:

@Test
public void whenParentSavedThenMerged() {
    int addressId;
    Person person = buildPerson("devender");
    Address address = buildAddress(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("devender kumar");
    savedAddressEntity.setHouseNumber(24);
    session.merge(savedPersonEntity);
    session.flush();
}

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

 

Also Read: Spring security basics

 

3.4. CascadeType.REMOVE

 

As the name suggests, the remove operation is used to remove the row corresponding to the entity from the database and also from the persistent context.

CascadeType.REMOVE propagates the removal operation from parent to following child entity. Similar to JPA's CascadeType.REMOVE, we have CascadeType.DELETE, which is specific to the Hibernate. There is no difference between the two.

Now, it's time to test CascadeType.Remove:

@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 queries :

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

The address associated with the person also got removed as a result of using CascadeType REMOVE.

 

Also Read: 5 Reasons Why Developers Prefer Kotlin Over Java

 

CascadeType.DETACH

 

The detach operation removes or detaches the entity from the persistent context. When we use CascaseType.DETACH, the child entity will eventually get removed from the persistent context.

Let's see it in action:

@Test
public void whenParentDetachedThenChildDetached() {
    Person person = buildPerson("devender");
    Address address = buildAddress(person);
    person.setAddresses(Arrays.asList(address));
    session.persist(person);
    session.flush();
    
    assertThat(session.contains(person)).isTrue();
    assertThat(session.contains(address)).isTrue();

    session.detach(person);
    assertThat(session.contains(person)).isFalse();
    assertThat(session.contains(address)).isFalse();
}

Here, we can see that after detaching or removing a person, neither person nor address exists in the persistent context.

 

CascadeType.LOCK

 

Unintuitively, CascadeType.LOCK re-attaches or again attaches the entity and its associated child entity with the persistent context again.

Let's see the test case to understand CascadeType.LOCK:

@Test
public void whenDetachedAndLockedThenBothReattached() {
    Person person = buildPerson("devender");
    Address address = buildAddress(person);
    person.setAddresses(Arrays.asList(address));
    session.persist(person);
    session.flush();
    
    assertThat(session.contains(person)).isTrue();
    assertThat(session.contains(address)).isTrue();

    session.detach(person);
    assertThat(session.contains(person)).isFalse();
    assertThat(session.contains(address)).isFalse();
    session.unwrap(Session.class)
      .buildLockRequest(new LockOptions(LockMode.NONE))
      .lock(person);

    assertThat(session.contains(person)).isTrue();
    assertThat(session.contains(address)).isTrue();
}

As we can see, when using CascadeType.LOCK, we attached the entity person and its associated address back to the persistent object.

 

Also Read: Creating Asynchronous Methods in Spring Boot

 

CascadeType.REFRESH

 

Refresh operations re-reads the value of a given instance from the database. In some cases, we can change an instance after persisting in the database, but later we need to undo those changes.

 

When we use this operation with CascadeType REFRESH, the child entity also gets reloaded from the database whenever the parent entity is also being refreshed.

let's see the following test case for CascadeType.REFRESH:

@Test
public void whenParentRefreshedThenChildRefreshed() {
    Person person = buildPerson("devender");
    Address address = buildAddress(person);
    person.setAddresses(Arrays.asList(address));
    session.persist(person);
    session.flush();
    person.setName("Devender Kumar");
    address.setHouseNumber(24);
    session.refresh(person);
    
    assertThat(person.getName()).isEqualTo("devender");
    assertThat(address.getHouseNumber()).isEqualTo(23);
}

 

Here, we have made some changes to the saved entity's person and address. When we refresh the person entity, the address is also going to get refreshed.

 

Choose Oodles For SaaS App Development Services

 

We are a 360-degree software development company that provides cross-platform SaaS app development services to address varied software project requirements. We have an experienced team of Java, PHP, and Python developers who use advanced frameworks, tools, and SDKs to build scalable web and mobile applications with custom features. For more detail, reach us out at info@oodlestechnologies.com.

About Author

Author Image
Simran Ahuja

Simran is a bright Java Developer,with good knowledge of core java and advanced java, always ready to face challenges and explore new places.

Request for Proposal

Name is required

Comment is required

Sending message..