detached entity passed to persist 에러
경위
JpaRepository
를 이용하여 ManyToOne 관계에 있는 두 도메인에 대한 클래스를 생성하고 DB에 저장하는 테스트를 실행했습니다.
증상
아래와 같은 문구를 띄우며 테스트 실패했습니다.
같은 객체(부모)를 참조하고 있는 서로 다른 두 개의 객체(자식)를 save(persist)하는 부분에서 에러가 발생했네요.org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: [package path]; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: [package path]
원인
@ManyToOne
의CascdeType
옵션을ALL
로 부여해서 발생한 문제였습니다.
영속성 전이 - cascade
특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속 상태로 만들고 싶다면 cascade
를 이용한 영속성 전이 기능을 사용하면 됩니다. JPA의 cascade
옵션으로 영속성 전이를 제공합니다.
쉽게 말해서 영속성 전이를 사용하면 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장할 수 있습니다.
CascadeType의 종류
CascadeType.RESIST
: 엔티티를 생성하고, 연관 엔티티를 추가하였을 때 persist() 를 수행하면 연관 엔티티도 함께 persist()가 수행된다. 만약 연관 엔티티가 DB에 등록된 키값을 가지고 있다면 detached entity passed to persist Exception이 발생한다.CascadeType.MERGE
: 트랜잭션이 종료되고 detach 상태에서 연관 엔티티를 추가하거나 변경된 이후에 부모 엔티티가 merge()를 수행하게 되면 변경사항이 적용된다.(연관 엔티티의 추가 및 수정 모두 반영됨)CascadeType.REMOVE
: 삭제 시 연관된 엔티티도 같이 삭제됨CascadeType.DETACH
: 부모 엔티티가 detach()를 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않는다.CascadeType.ALL
: 모든 Cascade 적용
JPA Life cycle
CascadeType.ALL
옵션을 주었기 때문에, 처음 save()
했을 때 자식 객체에서 참조하고 있는 부모객체가 detached
되었고, 다시 persist
가 불가능 했기에 에러가 발생했습니다.
해결법
casecade
옵션을 MERGED
혹은 DETACH
변경하거나 삭제합니다./*(cascade = CascadeType.ALL)*/
(cascade = CascadeType.MERGED)
(cascade = CascadeType.DETACH)