[QueryDSL]count() 값 Integer 타입으로 return 하기

god1hyuk·2022년 9월 14일
1

Trouble Shooting

목록 보기
5/6
post-thumbnail

시나리오

"n월의 리포트" (월간 리포트 : n월 동안의 Todo List 좋아요 현황, 달성 현황 등...) 페이지 에서 "n월의 총 좋아요 개수" 조회하기

요구사항

QueryDSL을 사용하여 n월의 총 좋아요 개수를 구하라.
(Integer 타입으로 return 해야 함)

문제점

likes 테이블에 todo_list 테이블을 join 하여 해당 member와 해당 month에 부합하는 likes를 찾아 likes 개수를 합산 하기 위해 count() 함수를 사용하였다.

public Integer findMonthlyTotalLikes(Member member, String month) {
        return queryFactory
                .select(likes.count())
                .from(likes)
                .innerJoin(todoList)
                .on(likes.todoList.eq(todoList))
                .where(todoList.member.eq(member), todoList.dueDate.contains(month))
                .fetchFirst();
    }

리스트 형태가 아닌 하나의 값을 반환해야 하기 때문에 fetch()가 아닌 fetchFirst()를 사용하였다.

하나의 값을 반환하는 fetch 타입이 두가지가 있는데 이 fetchFirst()와 fetchOne() 중 어떤 것을 사용할지 고민을 하다 fetchFirst()를 사용했다. 명확한 이유는 없었지만 fetchFirst()가 더 완전한 방법이라 생각이 들었다.

QueryDSL에 여러가지의 fetch 종류가 있다.

QueryDSL fetch 타입의 종류

  1. fetch() : 조회 대상이 여러건일 경우. 컬렉션 반환
  2. fetchOne() : 조회 대상이 1건일 경우(1건 이상일 경우 에러). generic에 지정한 타입으로 반환
  3. fetchFirst() : 조회 대상이 1건이든 1건 이상이든 무조건 1건만 반환. 내부에 보면 return limit(1).fetchOne() 으로 되어있음
  4. fetchCount() : 개수 조회. long 타입 반환
  5. fetchResults() : 조회한 리스트 + 전체 개수를 포함한 QueryResults 반환. count 쿼리가 추가로 실행된다.

출처 : https://joont92.github.io/jpa/QueryDSL/

fetchCount()나 fetchResults() 같은 경우는 IntelliJ 상에서 미들라인이 그어져 있어 뭔가 권장하지 않는 것 같아 일단 사용하지는 않았다.

본론으로 돌아와 이렇게 코드를 작성하면 쿼리상으로는 아무리 생각해도 문제가 없는데 코드에 문제가 있다고 한다.

IntelliJ에서는 이렇게 제안을 한다.

추측해보면 반환타입이 Integer가 될 수 없다는 것인데...
return 타입을 Long으로 변경하거나 쿼리문을 Math.toIntExact() 메소드로 wrapping을 하여 Integer 타입으로 형변환 해야 하는 상황이다.

n월의 총 좋아요 개수는 아무리 많아도 Long 타입을 사용할 만큼의 큰 수가 나올일이 없다고 생각한다. 그래서 Integer로 return 하고 싶었다.

처음에는 count()함수를 사용하면 Long 타입으로 반환 되는 건가 싶어count() 함수에 관해 검색을 했다.

내 추측이 맞았다.
JPA에서 count()는 Long 타입을 return 한다고 한다.

참고자료 : https://www.freeism.co.kr/wp/archives/1573

해결책

원하는 대로 Integer 타입으로 return 하기 위해 작성한 쿼리문을 Math.toIntExact()으로 wrapping 후 Integer 타입으로 형변환 하여 return 해주었다.

public Integer findMonthlyTotalLikes(Member member, String month) {
        return Math.toIntExact(queryFactory
                .select(likes.count())
                .from(likes)
                .innerJoin(todoList)
                .on(likes.todoList.eq(todoList))
                .where(todoList.member.eq(member), todoList.dueDate.contains(month))
                .fetchFirst());
    }

결과를 출력해보면

11개로 예상한 값이 잘 조회 되었다.
이로써 "n월의 총 좋아요 개수" 조회하기 성공 🙆‍♂️

1개의 댓글

comment-user-thumbnail
2022년 9월 15일

초록색 눈 아파요

답글 달기