Caused by: org.hibernate.query.SemanticException: Fetch join has a 'with' clause (use a filter instead)
Fetch join 시 with/on 절을 사용했더니 발생
-> Where 절에서 필터링 해야함
페치 조인은 객체 그래프를 함께 로딩하기 위해 사용하는 건데, on 조건을 사용하면 연관 엔티티의 일부만 조인되므로, 영속성 컨텍스트에 불완전한 객체가 들어갈 수 있어 위험
이게 무슨말이냐면, Post 엔터티가 Comment 컬렉션 엔터티를 가지고 있을 때, JPQL에서 Comment의 deleted = false로 조회하였다면, 나중에 post.getComments()를 호출해도 deleted = true인 것은 조회되지 않음. 왜냐면 JPA는 이미 fetch 했으니 다 있는 줄 알기 때문
해결 1. 조건 제거하고 로직에서 필터링
성능 문제 발생하여 현실적이지 않음
미래에도 데이터가 적을 경우에만 사용해도 될 것
해결 2. @BatchSize를 통한 Comment 별도 쿼리
Post 엔터티를 먼저 조회하고, Post ID를 기준으로 Comment 컬렉션 조회. 이 때 @BatchSize를 통해 N+1 문제를 IN 절로 어느 정도 해소한다
추천 기준
- Comment 엔터티의 변경/저장 필요할 때
- 구현 간결성, 유지보수 우선
해결 3. Comment DTO로 직접 조인 없이 가져와 코드에서 매핑
- Post 목록 조회
- Post ID로 Comment DTO 목록 조회
- Comment DTO 목록을 Map으로 만듦(<Post ID, Comment DTO>)
- Post에 Comment DTO 목록 매핑
추천 기준
- Comment 엔터티의 단순 조회
- 댓글 수가 많고 성능 중요
조회 시엔 DTO, 수정 시엔 엔터티 조회가 좋다
해결 4. Querydsl 사용
페치 조인 시 with/on 절 사용 가능 (오류 없음)
그런데 Fetch join with ON condition may cause incomplete entity graph라는 경고를 주긴한다
JPA 철학에는 맞지 않기에 가능하다면 DTO를 사용하는 것이 좋겠다
결론
단순히 회면에 보여주기 위해 연관관계가 있는 엔터티들을 한 번에 조회한다면, 엔터티가 아닌 DTO들로 조회하는 것이 좋다. 그리고 DTO 쿼리를 만들 때는 Querydsl이 훨씬 좋다는 것은 당연한 거고
'Spring > JPA' 카테고리의 다른 글
| Spring Data JPA > Query Methods > 메서드명 접두사 (0) | 2023.12.04 |
|---|