JPA

[JPA 오류] TransientPropertyValueException: object references an unsaved transient instance (One To One)

HSY_mumu 2022. 11. 7. 11:48
728x90

1. 문제 상황 및 원인

- 출금 계좌 등록 요청을 보냈을 때, memberExtra 객체가 아직 영속성 컨텍스트에 등록되지 않은 상태에서 memberExtra를 member 엔티티의 memberExtra 필드에 저장하려고 할 때 에러가 발생했다.

org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.example.mutbooks.app.member.entity.Member.memberExtra -> com.example.mutbooks.app.member.entity.MemberExtra
	at org.hibernate.engine.spi.CascadingActions$8.noCascade(CascadingActions.java:379) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:169) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:159) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:149) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:82) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1407) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:489) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3290) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2425) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:449) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
	at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]

 

1) MemberService 의 createBankInfo()

// 계좌 등록
@Transactional
public void createBankInfo(Member member, WithdrawAccountForm withDrawAccountForm) {
    MemberExtra memberExtra = MemberExtra.builder()
            .member(member)
            .bankName(withDrawAccountForm.getBankName())
            .bankAccountNo(withDrawAccountForm.getBankAccountNo())
            .build();
    member.modifyMemberExtra(memberExtra);
    // TODO: 계좌 정보는 memberContext 값에 담겨있지 않으므로 세션값 강제 수정할 필요X
    //forceAuthentication(member);
}

- memberExtra 를 아직 저장하지 않은 상태에서 member.modifyMemberExtra(memberExtra)를 호출 하게 되어 문제 발생

 

2) MemberExtra

public class MemberExtra extends BaseEntity {
    @OneToOne
    private Member member;          // 관련 회원

    private String bankName;        // 출금 은행명
    private String bankAccountNo;   // 출금 계좌번호
}

 

3) Member

public class Member extends BaseEntity {
    ...

    @OneToOne(mappedBy = "member")
    private MemberExtra memberExtra;
    
    ...
}

 

2. 해결 방법

부모 객체에 선언한 자식 객체에 CascadeType.ALL을 선언한다. 이를 통해 영속성 전이가 발생해 부모 객체를 저장할 때, 자식 객체도 함께 저장할 수 있다.

 

즉, Member 엔티티의 MemberExtra 필드 위에 CascadeType.ALL 을 추가한다.

public class Member extends BaseEntity {
    ...

    @OneToOne(mappedBy = "member", cascade = CascadeType.ALL)
    private MemberExtra memberExtra;
    
    ...
}

 

 

https://minholee93.tistory.com/entry/ERROR-JPA-TransientPropertyValueException-object-references-an-unsaved-transient-instance

 

[ERROR] JPA TransientPropertyValueException: object references an unsaved transient instance

1. 문제 JPA를 사용해 객체간 @OneToOne 관계를 설정한뒤 Repository의 save를 호출할때 아래와 같은 에러가 발생할 수 있다. 2. 원인 이러한 상황은 주로 부모객체에서 자식객체를 한번에 저장하려고할

minholee93.tistory.com

https://velog.io/@max9106/JPA%EC%97%94%ED%8B%B0%ED%8B%B0-%EC%83%81%ED%83%9C-Cascade

 

[JPA]엔티티 상태 & Cascade

cascade 옵션이란 @OneToMany 나 @ManyToOne에 옵션으로 줄 수 있는 값이다.Entity의 상태 변화를 전파시키는 옵션이다.만약 Entity의 상태 변화가 있으면 연관되어 있는(ex. @OneToMany, @ManyToOne) Entity에도 상태

velog.io

 

728x90