Post

Spring Data JPA - Difference Between Cascade and orphanRemoval

Spring Data JPA - Difference Between Cascade and orphanRemoval

This post was migrated from Tistory. You can find the original here.

Related post

2023.07.13 - [Spring/JPA] - Spring) JPA Entity options - lazy loading / cascading persistence / orphan entity removal (23-07-12)

[Spring) JPA Entity options - lazy loading / cascading persistence / orphan entity removal (23-07-12)

2023.07.13 - [spring] - Spring) JPA Entity relationships - owner of the foreign key (23-07-11) Continuing from the previous post JPA Entity Option FetchType EAGER/LAZY (lazy loading) public @interface ManyToOne{ … FetchType fetc

cornpip.tistory.com](https://cornpip.tistory.com/32)


If the data you’re trying to delete is being referenced as a foreign key in another table, you can’t delete it.

Say the entity you want to delete is Device, and Sensor holds a foreign key to Device.

  • Either delete the associated Sensor
  • Or set the Device foreign key on the associated Sensor to NULL

Either way, you have to break the relationship depending on Device before you can delete it.

CascadeType.REMOVE

CascadeType.REMOVE - when a Device is deleted, the associated Sensor is automatically deleted as well.

1
2
3
4
5
6
7
8
    // Device.java
    @OneToOne(mappedBy = "device", cascade = CascadeType.REMOVE)
    private Sensor sensor;
    
    // Sensor.java
    @OneToOne
    @JoinColumn(name = "device_id", referencedColumnName = "id")
    private Device device;

The same applies to one-to-many relationships — just put it on the parent side.

+) It’s also fine to use it on the foreign-key-owning side. Either way, when an entity with the cascade setting is deleted, its associated entity gets deleted too.

orphanRemoval = true

Same as with REMOVE, this goes on the parent side.

   
AspectCascadeType.REMOVEorphanRemoval = true
When it triggersWhen the parent entity is deletedWhen the child entity is removed from the relationship with the parent
Main delete triggerDeletion of the parentThe relationship with the parent being broken
Behavior when the relationship is brokenThe child entity remainsThe child entity is deleted
Requires explicit deletion?Requires the parent to be explicitly deletedDeleted automatically once the relationship is broken

I asked GPT about the difference between remove and orphanRemoval, and it gave me the table above.

With remove, the trigger is deletion of the parent entity — if you break the relationship some other way, the orphaned entity is not deleted.

With orphanRemoval, the trigger is the relationship being broken — no matter how the relationship is severed, the orphaned entity gets deleted.

1
2
3
4
5
6
7
8
    // Device.java
    @OneToMany(mappedBy = "device", orphanRemoval = true, cascade = CascadeType.PERSIST)
    private List<Sensor> sensors = new ArrayList<>();
    
    // Sensor.java
    @ManyToOne
    @JoinColumn(name = "device_id", referencedColumnName = "id")
    private Device device;

Let’s verify this.

1
2
3
4
5
6
7
8
9
10
11
12
13
    // TestCode
    @Test
    @Transactional
    @Rollback(value = false)
    void delete() {
        Optional<Device> byId = deviceRepository.findById(4L);
        if (byId.isPresent()) {
            Device device = byId.get();
            List<Sensor> sensors = device.getSensors();
            sensors.set(1, null);
            deviceRepository.save(device);
        }
    }

If we break the relationship by setting a null value instead of deleting the parent entity:

  • With CascadeType.REMOVE, the relationship is broken but the now-unused Sensor is not deleted.
  • With orphanRemoval = true, the orphaned Sensor is deleted.

Whatever business you’re providing a computerized solution for, you’ll typically end up using a relational DB, and that brings a lot of relationships along with it.

Along the way, it’s easy to forget to wire up an FK that should be connected, or forget to break an FK that should be broken.

The more complex the ERD, the longer it takes just to reproduce the CRUD flows — but writing tests still seems to be the best way to catch the parts you’d otherwise miss.

This post is licensed under CC BY-NC 4.0 by the author.