[Spring] CascadeType.REMOVE 그리고 orphanRemoval = true
A A

CascadeType.REMOVE vs. orphanRemoval = true 차이?

  CascadeType.REMOVE orphanRemoval = true
부모 엔티티 삭제 자식 엔티티도 삭제됨 부모 삭제시 자식 엔티티도 삭제됨 
(부모가 자식의 삭제 생명주기 관리)
부모-자식 연관관계 제거 단순 연관관계 제거만으로는
자식 엔티티는 삭제되지 아니함
자식 엔티티 = 고아 객체 취급
자동으로 DB에서 삭제됨
부모-자식 연관관계 변경 잘 변경됨 잘 변경됨 

 

 

한편, CascadeType.PERSIST와 CascadeType.REMOVE의 차이?

 

  • persist: 새로운 엔티티를 영속성 컨텍스트에 저장하여 DB에 추가.
  • remove: 이미 존재하는 엔티티를 영속성 컨텍스트에서 제거하고 DB에서 삭제.

 

예시

// persist 예시
Order newOrder = new Order();  // 새로운 객체
newOrder.setDate(LocalDate.now());
entityManager.persist(newOrder);  // DB에 저장

// remove 예시
Order existingOrder = entityManager.find(Order.class, 1L);  // DB에서 조회
entityManager.remove(existingOrder);  // DB에서 삭제

 


 

예시 상황

 

CascadeType.REMOVE

주문(Order)과 주문 상세(OrderDetail)

  • Order 엔티티가 삭제되면 OrderDetail도 함께 삭제되어야 하는 경우
  • Order는 여러 OrderDetail을 가질 수 있지만, Order가 삭제되면 관련된 OrderDetail도 삭제되어야 함.

-> CascadeType.REMOVE가 설정된 경우, Order 엔티티가 삭제되면 관련된 OrderDetail도 자동으로 삭제

더보기
@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private LocalDateTime orderDate;

    @OneToMany(mappedBy = "order", cascade = CascadeType.REMOVE)
    private List<OrderDetail> orderDetails = new ArrayList<>();
}
@Entity
public class OrderDetail {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private int quantity;
    private BigDecimal price;

    @ManyToOne
    @JoinColumn(name = "order_id")
    private Order order;
}

 

 

orphanRemoval = true

회원(User)과 즐겨 찾기 레시피(UserFavoriteRecipe)

  • User는 여러 UserFavoriteRecipe를 가질 수 있지만, 사용자가 특정 레시피를 즐겨찾기에서 제거하면 해당 레시피는 자동으로 삭제되어야 하는 경우
더보기
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<UserFavoriteRecipe> favoriteRecipes = new ArrayList<>();
}
@Entity
public class UserFavoriteRecipe {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne
    @JoinColumn(name = "recipe_id")
    private Recipe recipe;
}

 

 


 

 

간단한 판단 기준:

  • 부모가 삭제될 때 자식도 삭제되어야 할 경우: CascadeType.REMOVE
  • 자식이 부모와의 연관 관계를 끊었을 때 자식만 삭제되어야 할 경우: orphanRemoval = true

 

두 옵션을 동시에 사용할 수 있는 경우:

  • 부모 삭제 시 자식도 삭제되고, 자식이 부모와의 관계를 끊었을 때도 자식이 삭제되어야 한다면 두 옵션을 함께 사용할 수 있음.

 


 

 

번외

CascadeType.ALL에 포함된 Cascade 옵션:
- CascadeType.PERSIST: 부모 엔티티가 저장될 때, 자식 엔티티도 자동으로 저장됩니다.
- CascadeType.MERGE: 부모 엔티티가 병합될 때, 자식 엔티티도 자동으로 병합됩니다.
- CascadeType.REMOVE: 부모 엔티티가 삭제될 때, 자식 엔티티도 자동으로 삭제됩니다.
- CascadeType.REFRESH: 부모 엔티티가 새로고침될 때, 자식 엔티티도 자동으로 새로고침됩니다.
- CascadeType.DETACH: 부모 엔티티가 분리될 때, 자식 엔티티도 자동으로 분리됩니다.
Copyright 2024. GRAVITY all rights reserved