[Trouble Shooting] TransientPropertyValueException: object references an unsaved transient instance 해결
문제 상황
엔티티 클래스 작성 후 서버를 실행하고, 포스트맨을 이용해 요청하는 도중에 해당 에러가 발생하였다.
문제 원인
영속성때문에 나는 오류이다.
FK로 쓰는 객체가 아직 저장이 안 되어서 오류가 발생한다고 한다.
객체간 @OneToMany
, @ManyToOne
같은 어노테이션을 사용할 때 발생할 수 있다.
내 경우에는, 관계 정의가 아래와 같이 되어있었는데
Pet
클래스에서 에러가 발생했다.
위 엔티티를 조금 간소화해서 설명하자면,
User (id, username, password)
이라는 테이블과 Pet (id, petName, user_id)
이라는 테이블 관계가 있을 때,
User
데이터를 넣지 않고 Pet
데이터를 넣으려고 하면 user_id
값이 없어서 에러가 발생하는 것이다.
User user = new User("test123", "password");
Pet pet = new Pet("Yebbi", user);
petRepository.save(pet); // 에러 발생 (user 의 id 값을 모르는데 테이블에 넣으려고 해서)
해결 방법
연관 관계 매핑해줄 때 사용하는 @ManyToOne
, @OneToOne
, @OneToMany
어노테이션에 cascade 옵션을 설정해준다.
cascade 는 “영속성 전이” 라고 하는 개념인데 특정 엔티티를 영속화 할 때 연관된 엔티티도 함께 영속화 한다.
저장할 때만 사용하려면 cascade = CascadeType.PERSIST
로 설정해주면 되며, 전체 적용인 CascadeType.ALL
로 설정해도 된다.
그럼 Pet 데이터를 저장하기 전에 User 값부터 저장한다.
Pet
클래스의 변경 전과 후의 코드를 보면 이해가 쉬울 것이다.
변경 전
@Entity
@Getter
public class Pet {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ownerId")
private User owner;
}
변경 후
@Entity
@Getter
public class Pet {
...
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "ownerId")
private User owner;
}
💛 개인 공부 기록용 블로그입니다. 👻