[Error] TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing
스프링부트에서 Spring Data JPA를 공부 하던 중 Repository를 테스트하는 중 아래와 같은 TransientPropertyValueException 오류가 발생했다.
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : project.toyproject.domain.Product.member -> project.toyproject.domain.Member; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : project.toyproject.domain.Product.member -> project.toyproject.domain.Member
테스트코드는 다음과 같다.
@DisplayName("전체 상품 조회")
@Test
void findAll() {
Product product = createProduct();
Product save = productJpaRepository.save(product);
Member member = createMember();
Product product2 = Product.createProduct("test2", "tt.jpg", "test2", 20000, member, CategoryList.BOOKS);
productJpaRepository.save(product2);
List<Product> all = productJpaRepository.findAll();
원인
구글링 결과 원인은 영속성 때문에 발생하는 오류이다.
FK로 사용되는 컬럼값이 없는 상태에서 데이터를 넣으려다 발생한 에러이다.
나의 코드 경우 Member 데이터를 넣지않고 Product 데이터를 넣으려고 하면 Member_id값이 없기 때문에 발생하는 에러이다.
해결
연관 관계를 매핑할 때 사용하는 @ManyToOne, @OneToOne, @OneToMany 어노테이션에 cascade를 설정해주면 된다.
join 하는 쪽에 아래 코드와 같이 설정해주었다.
@ManyToOne(fetch = LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "member_id")
private Member member; //fk
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 적용
CascadeType.ALL 주의
예전에 한 번 CascadeType.ALL로 인해 PersistentObjectException: detached entity passed to persist라는 에러를 겪은 기억이 있다.
JPA에서 자동으로 생성되는 값을 가진 필드에 직접적으로 값을 넣어 저장하고자 할 때 발생한다.
CascadeType.ALL로 개발하다 다시 저 오류가 발생하게 되면 다시 정리해야겠다.