일대다 관계에서는 다 쪽이 외래 키를 관리하게 됩니다. JPA 상에서는 왜래 키가 갖는 쪽이 연관 관계의 주인이 되고 연관 관계의 주인만이 데이터베이스 연관 관계와 매핑되고 왜래 키를 관리(등록, 수정, 삭제)할 수 있으므로 DeliveryLog에서 Delivery를 관리하게 됩니다. 하지만 DeliveryLog는 Delivery 상태를 저장하는 로그 성격 이기 때문에 핵심 비즈니스 로직을 Delivery에서 작성하는 것이 바람직합니다.
이럴 때 편의 메소드와 Cascade 타입 PERSIST 이용하면 보다 이러한 문제를 해결 할 수 있습니다.
CaseCade PERSIST을 통해서 Delivery 엔티티에서 DeliveryLog를 생성할수 있게 설정합니다. CaseCade PERSIST가 없을 때 실제 객체에는 저장되지만, 영속성 있는 데이터베이스에 저장에 필요한 insert query가 동작하지 않습니다.
JPA를 잘활용하면 도메인의 의도가 분명하게 들어나도록 개발할 수 있다는 것을 강조드리고 싶습니다.
고아 객체 (orphanRemoval)
JPA는 부모 엔티티와 연관 관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공하는데 이것을 고아 객체 제거라 합니다. 이 기능을 사용해서 부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티티가 자동으로 삭제 돼서 개발의 편리함이 있습니다.
DeliveryLog 삭제
1 2 3 4 5
public Delivery removeLogs(long id){ final Delivery delivery = findById(id); delivery.getLogs().clear(); // DeloveryLog 전체 삭제 return delivery; // 실제 DeloveryLog 삭제 여부를 확인하기 위해 리턴 }
delivery, deliverylog 참조 관계를 맺고 있어 Delivery만 삭제할 수 없습니다. delete SQL을 보시다시피 delivery_log 부터 제거 이후 delivery를 제거하는 것을 알 수 있습니다. 이처럼 orphanRemoval 속성으로 더욱 쉽게 삭제 할 수 있습니다.
orphanRemoval 설정이 없는 경우
DeliveryLog 삭제 같은 경우에는 실제 객체에서는 clear() 메서드로 DeliveryLog가 삭제된 것처럼 보이지만 영속성 있는 데이터를 삭제하는 것은 아니기에 해당 Delivery를 조회하면 DeliveryLog가 그대로 조회됩니다. 실수하기 좋은 부분이기에 반드시 삭제하고 조회까지 해서 데이터베이스까지 확인하시는 것을 권장해 드립니다.