저의 개발 환경은 다음과 같습니다.
- spring-boot-starter-web:2.3.1
- spring-boot-starter-data-jpa:2.3.1
- spring-boot-postgresql:42.2.14
- junit:junit:4.13
안녕하세요.
테스트 코드를 작성하면서 다음과 같은 hibernate 예외를 만났습니다.
unable to evaluate the expression Method threw 'org.hibernate.LazyInitializationException' exception
테스트 코드의 작성 내용은 다음과 같습니다.
1. 사용 객체
- Event(모임) @OneToMany(mappedBy = "event")
- Enrollment(모임에 등록한 멤버의 등록 정보 객체) @ManyToOne
- 양방향 관계
2. 테스트 내용
- 모임에 참가를 신청한 Enrollment객체가 정상적으로 등록이 되는지 확인.
Entity관계는 다음과 같습니다.
테스트 코드를 디버그 찍어보면서 Event객체에 들어있는 값을 확인한 결과 다음과 같았습니다.
enrollments의 값을 확인하는 테스트를 진행하고 있는데, enrollments의 값에서 저런 이슈 메시지가 발생하고 있었습니다.
생각해본 결과, 제가 Event에 의존하는 Enrollments에서 값을 확인하려고 했기 때문이었습니다.
자세히 말하자면,
위에도 적혀있지만, Event객체에서 Enrollment객체와의 관계는 @OneToMany로 정의되어 있습니다.
@OneToMany는 기본적으로 LazyLoading입니다. 그렇게 때문에 Event객체를 JPA를 사용해서 데이터를 가져와도 Event 객체의 @OneToMany관계로 매핑이 된 Enrollments의 값은 가져오지 않습니다. 그래서 LazyInitializationException으로 예외가 발생하고 있었습니다. 이런 경우는 assertNull()로 해도 에러가 납니다.
해결방법
양방향 관계이므로, @ManyToOne의 객체 쪽에서 데이터를 가져오면 됩니다. @ManayToOne 객체는 fetch타입이 'EAGER' 타입입니다. JPA로 객체를 가져올 때, @ManyToOne으로 설정한 객체의 데이터도 함께 가져오게 됩니다.
아래처럼 주객체인 Event객체에서 enrollments의 정보를 확인하는 것이 아니라, 실제 객체인 Enrollment 객체의 JpaRepository를 상속받는 객체인 enrollmentRepository를 사용해서 모임과 모임에 참여하는 계정으로 해당 enrollment를 찾는 것으로 확인하면 되었습니다.
결론적으로 이번 테스트코드를 작성하면서 알게된 내용은.
@OneToMany(fetch=FetchType.LAZY)
@ManyToOne(fetch=FetchType.EAGER)
@OneToMany로 선언한 value값을 가지는 객체(주인 객체)가 JPA를 통해 데이터베이스에 값을 불러오면 @OneToMany의 타겟이 되는 객체(하인객체)의 값은 가져오지 않습니다.
감사합니다.
'SpringBoot > JPA' 카테고리의 다른 글
JPA로 객체를 가져올 때 LazyLoading을 만난 썰 (0) | 2020.09.27 |
---|---|
다대다관계에서 ORM하는 법 (0) | 2020.09.11 |
[JPA] 자바 영속성 어노테이션 알아보기 (0) | 2020.07.05 |
댓글