JAVA/JPA

[JPA] CascadeType.REMOVE vs orphanRemoval = true

민트맛녹차 2022. 3. 19. 23:32

토이프로젝트 중 CascadeType.REMOVE 와 orphanRemoval = true 가 헷갈려 둘의 차이를 찾고 정리하였다.

당시 상황은 다음과 같다.

@Entity
@Getter
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "order_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL) 
    @JoinColumn(name = "delivery_id")
    private Delivery delivery;

    @OneToMany(mappedBy = "order",cascade = CascadeType.ALL)
    private List<OrderItem> orderItems = new ArrayList<OrderItem>();

    private int expectedTime;

}

 

엔티티 설계 중 Order이 Delivery와 OrderItem의 영속성을 관리하기 원했다. Delivery와 OrderItem의 생명주기가 Order에 종속적이고, Delivery와 OrderItem의 Repository를 추가적으로 생성하지 않고 OrderRepository 하나로 Delivery와 OrderItem의 영속성을 관리할 수 있기 때문이다. 따라서 Order의 delivery와 orderItems에 CascadeType.ALL 속성을 부여했다. 이때 orphanRemoval = true를 추가해야 하는지 의문이 들었고, CascadeType.REMOVE와 orphanRemoval = true의 차이점에 대해 다시 생각해 보았다.

 

CascadeType.REMOVE

CASCADE는 영속성을 전이할 때 쓰이는 옵션이다. 즉 부모 엔티티를 영속화 할때 연관된 자식 엔티티도 함께 영속화 시키는 기능을 제공한다.

그 중 CascadeType.REMOVE 옵션은 부모 엔티티가 삭제되면 자식 엔티티도 삭제된다. 

Order order1 = em.find(Order.class,id);
order1.getOrderItems().remove(0);

하지만 위 코드처럼 부모 엔티티가 자식 엔티티의 관계를 끊는 경우, 즉 부모 엔티티에서 자식 엔티티를 삭제하는 경우는 자식 엔티티는 삭제되지 않는다.

orphanRemoval = true

orphanRemoval은 고아 객체 제거 옵션으로 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공한다. 

부모 엔티티를 삭제하면 자식 엔티티는 고아 객체가 되므로 자식 엔티티도 삭제된다. 또한 부모 엔티티에서 자식 엔티티를 삭제하는 경우도 자식 엔티티는 고아 객체 취급되어 삭제된다.

 

그래서 CascadeType.ALL을 추가한 뒤, orphanRemoval = true도 추가해야 하나??

정리하자면 CascadeType.REMOVE 와 orphanRemoval = true 옵션은 부모 엔티티가 삭제될 때는 같은 동작을 하지만 부모 엔티티와 자식 엔티티의 관계가 끊어질 때는 다른 동작을 한다.

따라서 부모 엔티티가 자식 엔티티와의 관계를 끊을 때 자식 엔티티가 삭제되길 원한다면 orphanRemoval = true 옵션을 추가하면 된다.

 

 

참조
자바 ORM 표준 JPA 프로그래밍 - 기본편
https://tecoble.techcourse.co.kr/post/2021-08-15-jpa-cascadetype-remove-vs-orphanremoval-true/