QueryDSL
발생 에러
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
[FromElement
{
explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=
board,role=com.teamproj.backend.model.board.BoardLike.board,
tableName=board,tableAlias=board1_,
origin=board_like boardlike0_,
columns={boardlike0_.board_board_id,
className=com.teamproj.backend.model.board.Board
}
}
]
select board.boardId, board.thumbNail, board.title, user.nickname, count(boardLike.board) as c
from com.teamproj.backend.model.board.BoardLike boardLike
left join fetch boardLike.board as board
left join fetch boardLike.user as user
where board.boardCategory = ?1
and boardLike.createdAt between ?2
and ?3
group by boardLike.board
order by c desc
인용문은 복사 붙여넣기 할 때 엔터가 적용이 안 돼서 자바 코드블럭으로 올리는 점 양해 바란다..... 티스토리 조금 나를 서운하게 하네?
에러 발생 코드
private List<Tuple> getYesterdayLikeCountRankTuple(BoardCategory boardCategory, int count) {
QBoardLike qBoardLike = QBoardLike.boardLike;
QBoard qBoard = QBoard.board;
QUser qUser = QUser.user;
LocalDateTime startDatetime = LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(0, 0, 0)); //어제 00:00:00
LocalDateTime endDatetime = LocalDateTime.of(LocalDate.now(), LocalTime.of(23, 59, 59)); //오늘 23:59:59
NumberPath<Long> likeCnt = Expressions.numberPath(Long.class, "c");
return queryFactory.select(qBoard.boardId, qBoard.thumbNail, qBoard.title, qUser.nickname, qBoardLike.board.count().as(likeCnt))
.from(qBoardLike)
.leftJoin(qBoardLike.board, qBoard)
.fetchJoin()
.leftJoin(qBoardLike.user, qUser)
.fetchJoin()
.where(qBoard.boardCategory.eq(boardCategory)
.and(qBoardLike.createdAt.between(startDatetime, endDatetime)))
.groupBy(qBoardLike.board)
.orderBy(likeCnt.desc())
.limit(count)
.fetch();
}
에러 발생 이유 : DTO 형식의 반환형에 fetchJoin()을 실시하여 발생
문제 해결 : fetchJoin()을 제거하여 해결.
private List<Tuple> getYesterdayLikeCountRankTuple(BoardCategory boardCategory, int count) {
QBoardLike qBoardLike = QBoardLike.boardLike;
QBoard qBoard = QBoard.board;
QUser qUser = QUser.user;
LocalDateTime startDatetime = LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(0, 0, 0)); //어제 00:00:00
LocalDateTime endDatetime = LocalDateTime.of(LocalDate.now(), LocalTime.of(23, 59, 59)); //오늘 23:59:59
NumberPath<Long> likeCnt = Expressions.numberPath(Long.class, "c");
return queryFactory.select(qBoard.boardId, qBoard.thumbNail, qBoard.title, qUser.nickname, qBoardLike.board.count().as(likeCnt))
.from(qBoardLike)
.leftJoin(qBoardLike.board, qBoard)
//.fetchJoin()
.leftJoin(qBoardLike.user, qUser)
//.fetchJoin()
.where(qBoard.boardCategory.eq(boardCategory)
.and(qBoardLike.createdAt.between(startDatetime, endDatetime)))
.groupBy(qBoardLike.board)
.orderBy(likeCnt.desc())
.limit(count)
.fetch();
}
근데, 문제를 이 방식으로 해결했을 때 남는 잠재적 위험성이 하나 있다. fetchJoin을 실시하지 않을 시 N+1 문제에서 자유로울 수 없다는 점이다. 현재의 경우 추가적인 조회 수요가 발생하지 않는 작업이기 때문에 이렇게 해결을 해도 상관은 없지만, 항상 적용할 수 있는 솔루션은 아니라는 점을 명심해야 할 것이다.
N+1 문제까지 해결한 문제에 대한 StackOverFlow 글이 있는 것 같다.(아직 해석은 안 해봤다)
혹시 N+1 문제도 해결하고 싶다면 아래 링크를 한 번 읽어보는 것을 추천한다. 나도 아직 해석은 안 해봐서 명쾌한 해답이 되는지는 잘 모르겠다.
'내가 배운 것들 > 문제 해결' 카테고리의 다른 글
[Ubuntu] 서버 시간 설정하는 방법 (0) | 2022.01.12 |
---|---|
[Redis] Redis에서 불러온 값이 for each문의 조건이 될 수 없는 문제 (0) | 2022.01.06 |
[Ubuntu/SpringBoot] Ubuntu 8080 포트를 80 포트로 포트포워딩 하기 (0) | 2021.12.29 |
[SpringBoot] JPA를 이용한 Delete가 실행되지 않는 현상 (0) | 2021.12.27 |
[SpringBoot/Redis/Ubuntu] 우분투 환경에 Redis 설치, SpringBoot에 세팅 (0) | 2021.12.27 |
댓글