Home > Spring > πŸƒ[Spring] JPAμ—μ„œμ˜ orphanRemoval μ˜΅μ…˜

πŸƒ[Spring] JPAμ—μ„œμ˜ orphanRemoval μ˜΅μ…˜
Spring Framework

πŸƒ[Spring] JPAμ—μ„œμ˜ orphanRemoval μ˜΅μ…˜.

  • orphanRemoval μ˜΅μ…˜μ€ JPAμ—μ„œ λΆ€λͺ¨ μ—”ν‹°ν‹°μ™€μ˜ 연관관계가 λŠμ–΄μ§„ Orphan Object(κ³ μ•„ 객체)λ₯Ό μžλ™μœΌλ‘œ μ‚­μ œν•˜λŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.
  • λΆ€λͺ¨ μ—”ν‹°ν‹°μ—μ„œ μžμ‹ μ—”ν‹°ν‹°μ™€μ˜ 관계λ₯Ό μ œκ±°ν•  λ•Œ, λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œλ„ μžλ™μœΌλ‘œ ν•΄λ‹Ή μžμ‹ μ—”ν‹°ν‹°κ°€ μ‚­μ œλ˜λ„λ‘ ν•˜λŠ” μ˜΅μ…˜μž…λ‹ˆλ‹€.

1️⃣ orphanRemoval μ‚¬μš© μ˜ˆμ‹œ.

  • λΆ€λͺ¨ μ—”ν‹°ν‹° Order와 μžμ‹ μ—”ν‹°ν‹° OrderItem κ°„μ˜ 1:N κ΄€κ³„μ—μ„œ orphanRemoval = trueλ₯Ό μ„€μ •ν•˜λ©΄, Orderμ™€μ˜ 관계가 끊긴 OrderItem κ°μ²΄λŠ” λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μžλ™μœΌλ‘œ μ‚­μ œλ©λ‹ˆλ‹€.
    ```java
    @Entity
    public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String customerName;

    @OneToMany(mappedBy = β€œorder”, cascade = Cascade = CascadeType.ALL, orphanRemoval = true)
    private List orderItems = new ArrayList<>();

    // 연관관계 편의 λ©”μ„œλ“œ
    public void addOrderItem(OrderItem item) {
    orderItems.add(item);
    item.setOrder(this);
    }

    public void removeOrderItem(OrderItem item) {
    orderItems.remove(item);
    item.setOrder(null); // λΆ€λͺ¨μ™€μ˜ 관계λ₯Ό 끊음
    }

    // getter, setter
    }

@Entity
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String productName;
private int quantity;

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

// getter, setter } ```

2️⃣ orphanRemoval μž‘λ™ 방식

  • Order μ—”ν‹°ν‹°μ—μ„œ orderItems ν•„λ“œμ— orphanRemoval = trueλ₯Ό μ„€μ •ν–ˆμŠ΅λ‹ˆλ‹€.
  • removeOrderItem() λ©”μ„œλ“œλ₯Ό 톡해 orderItems λ¦¬μŠ€νŠΈμ—μ„œ OrderItem 객체λ₯Ό μ œκ±°ν•˜κ³ , OrderItem의 order ν•„λ“œλ₯Ό null둜 μ„€μ •ν•΄ λΆ€λͺ¨μ™€μ˜ 관계λ₯Ό λŠμŠ΅λ‹ˆλ‹€.
  • μ΄λ•Œ orphanRemoval = true둜 μ„€μ •λ˜μ–΄ 있기 λ•Œλ¬Έμ—, JPAλŠ” 관계가 λŠμ–΄μ§„ OrderItem 객체λ₯Ό μžλ™μœΌλ‘œ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ‚­μ œν•©λ‹ˆλ‹€.

3️⃣ 예제 μ½”λ“œ μ‹€ν–‰.

Order order = new Order();
order.setCustomerName("Alice");

OrderItem item1 = new OrderItem();
item1.setProductName("Laptop");
item1.setQuantity(1);

OrderItem item2 = new OrderItem();
item2.setProductName("Mouse");
item2.setQuantity(2);

order.addOrderItem(item1);
order.addOrderItem(item2);

entityManager.persist(order); // Order와 OrderItem듀이 ν•¨κ»˜ μ €μž₯됨

order.removeOrderItem(item1); // Orderμ™€μ˜ 관계λ₯Ό 끊음
entityManager.merge(order); // item1은 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μžλ™μœΌλ‘œ μ‚­μ œλ¨

4️⃣ orphanRemovalκ³Ό CascadeType.REMOVE의 차이점.

  • CascadeType.REMOVE
    • λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μ‚­μ œλ  λ•Œ μ—°κ΄€λœ μžμ‹ μ—”ν‹°ν‹°λ₯Ό μ‚­μ œν•©λ‹ˆλ‹€.
  • orphanRemoval = true
    • λΆ€λͺ¨μ™€μ˜ 관계가 끊긴 Orphan Object(κ³ μ•„ 객체)λ₯Ό μžλ™μœΌλ‘œ μ‚­μ œν•©λ‹ˆλ‹€.
      • λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μ‚­μ œλ˜μ§€ μ•Šλ”λΌλ„ 관계가 끊긴 μžμ‹ μ—”ν‹°ν‹°λ§Œ κ°œλ³„μ μœΌλ‘œ μ‚­μ œλ©λ‹ˆλ‹€.

5️⃣ orphanRemoval μ‚¬μš© μ‹œ 주의 사항.

  • 1:N κ΄€κ³„μ—μ„œ μžμ‹ μ—”ν‹°ν‹°μ˜ 생λͺ…μ£ΌκΈ°κ°€ λΆ€λͺ¨ 엔티티에 쒅속될 λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.
  • μ–‘λ°©ν–₯ κ΄€κ³„μ—μ„œ orphanRemoval을 μ„€μ •ν•  경우, μˆœν™˜ μ°Έμ‘°λ‚˜ 예기치 μ•Šμ€ μ‚­μ œκ°€ λ°œμƒν•˜μ§€ μ•Šλ„λ‘ μ–‘μͺ½ ν•„λ“œλ₯Ό λͺ¨λ‘ 관리해야 ν•©λ‹ˆλ‹€.
  • 잘λͺ» μ‚¬μš©ν•˜λ©΄ μ˜λ„μΉ˜ μ•Šμ€ 데이터 μ‚­μ œκ°€ λ°œμƒν•  수 μžˆμœΌλ―€λ‘œ, λΆ€λͺ¨ 엔티티와 μžμ‹ μ—”ν‹°ν‹°μ˜ 관계가 ν™•μ‹€νžˆ 쒅속적인 κ²½μš°μ—λ§Œ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

6️⃣ μš”μ•½.

  • orphanRemoval μ˜΅μ…˜μ€ λΆ€λͺ¨μ™€μ˜ 연관관계가 끊긴 μžμ‹ μ—”ν‹°ν‹°(Orphan Object, κ³ μ•„ 객체)λ₯Ό μžλ™μœΌλ‘œ μ‚­μ œν•˜λŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€.
  • CascadeType.REMOVEμ™€λŠ” λ‹€λ₯΄κ²Œ λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μ‚­μ œλ˜μ§€ μ•Šμ•„λ„ 관계가 끊긴 μžμ‹ μ—”ν‹°ν‹°λ§Œ μ‚­μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€.