본문 바로가기

개발/Spring

[Querydsl] PageableExecutionUtils count query 오류

회원 목록을 불러올 때 회원 등급으로 필터링을 해보는데, 다른 등급은 잘 불러와지다가 일반 등급일 때만 api에서 서버 에러가 발생했다. 테스트 서버에서 에러가 발생하고 로컬에서 다시 테스트를 할 때는 또 정상으로 불러와졌다. 서비스를 개시한지 꽤 지난 시점에서 잘 되던 필터가 왜 오류 나는 것일까?


회원은 여러 개의 회원 등급을 가질 수 있다. 그래서 해당 회원 등급을 가진 경우를 필터링 한다. member와 memberRoles는 1:N 관계를 가진다.


Member Query Repository

public Page<Member> getMemberList(MemberRole memberRole, Pageable pageable) {
        List<Member> members = queryFactory
                .select(member)
                .from(member)
                .join(member.memberRoles, memberRoles)
                .where(
                        memberRolesEq(request.getMemberRole())
                )
                .orderBy(member.id.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

        JPAQuery<Long> countQuery = queryFactory
                .select(member.count())
                .from(member)
                .where(
                        memberRolesEq(request.getMemberRole())
                );

        return PageableExecutionUtils.getPage(members, pageable, countQuery::fetchOne);
}

private BooleanExpression memberRolesEq(MemberRole memberRole) {
    return memberRole != null ? memberRoles.memberRole.eq(memberRole) : null;
}

일반 회원을 필터링 하는 조건에서만 계속해서 아래 에러가 발생했다.


Caused by: java.lang.IllegalArgumentException: org.hibernate.query.PathException: Plural path 'domain.Member(member1).memberRoles' refers to a collection and so element attribute 'memberRole' may not be referenced directly (use element() function)


org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.query.PathException: Plural path 'domain.Member(member1).memberRoles' refers to a collection and so element attribute 'memberRole' may not be referenced directly (use element() function)


지금까지는 회원 수가 pageSize보다 적어 count 쿼리가 수행이 안됐었는데 회원이 많아지면서 count 쿼리가 실행되면서 count 쿼리에 join 구문이 없어 에러가 발생한 것이었다. join 하지 않은 엔티티에 조건을 넣으려니 에러가 발생.


count 쿼리에 아래와 같이 join 구문을 넣으니 에러가 해결되었다.

JPAQuery<Long> countQuery = queryFactory
        .select(member.count())
        .from(member)
        .join(member.memberRoles, memberRoles)
        .where(
                memberRolesEq(request.getMemberRole()),
        );

PageableExecutionUtils.getPage()의 마지막 인자로 totalCount를 구하는 쿼리 함수를 전달하는데 totalCount가 pageSize보다 작거나, 마지막 페이지 일 경우 해당 함수를 실행하지 않아 불필요한 쿼리를 줄일 수 있다. (최적화)