Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Querydsl 사용자 정의 레포지토리 & 페이징

Table of contents

  1. 사용자 정의 레포지토리
  2. 스프링 데이터 페이징 활용

사용자 정의 레포지토리

사용자 정의 레포지토리는, JPARepository가 기본적으로 제공하는 메서드가 아닌, 구현부를 직접 작성해야할 때 필요하다.

특히, 조건문이 까다로운 동적 쿼리같은 경우는 Querydsl을 사용해서 직접 구현할 필요가 있다.


먼저 JPARepository 를 상속받는 객체 레포지토리 인터페이스를 생성한다.

객체 레포지토리에는 JPA 메서드 명명규칙에 따라 만들 수 있는 메서드들을 만든다.

//예시

public interface MemberRepository extends JpaRepository<Member, Long> {

}


JpaRepository에 의해 자동으로 구현되는 메서드가 아닌, 사용자가 직접 원하는 구현체가 필요한 메서드는,

먼저 Custom 인터페이스를 하나 생성하고 추상메서드를 작성한다.

// 예시

public interface MemberRepositoryCustom{
    List<Member> search(Condition condition);
        //Condition은 조건문으로 사용하고 싶은 객체들을 담아둔 사용자가 직접 정의한 객체
}


그리고 그 Custom을 엔티티로 사용하는 객체 이름을 따서, [객체RepositoryImpl] 의 이름으로 implements 받은 뒤 구현부를 작성한다.

// 예시

public class MemberRepositoryImpl implements MemberRepositoryCustom{
    @Override
    List<Member> search(Condition condition){
        .....
    }
}


이제, 직접 구현한 클래스가 아닌, 인터페이스로 정의해놓은 MemberRepositoryCustom을 같이 상속받도록 설정해두면 된다.

//예시

public interface MemberRepository extends JpaRepository<Member, Long>,MemberRepositoryCustom {

}


스프링 데이터 페이징 활용


스프링 데이터의 PagePageable 를 활용해야 한다!

public interface MemberRepositoryCustom {
    //단순
    Page<객체> searchPageSimple(Condition condition, Pageable pageable);
    //복잡 (카운트 쿼리 분리)
    Page<객체> searchPageComplex(Condition condition, Pageable pageable);
}


구현체에서, 파라미터로 받은 Pageable 클래스의 메서드를 queryfactory와 함께 사용한다.

fetch 가 아닌 .fetchResults() 를 사용하면, 카운트 쿼리도 함께 실행된다.

.offset(pageable.getOffSet()) //몇번째 부터 시작할 것인가
.limit(pageable.getPageSize()) //몇개씩 나눌 것인가
.fetchResults();


List<객체> content = results.getResults();
long total = results.getTotal();

return new PageImpl<>(content,pageable,total);

fetchResults를 사용한 덕분에, 결과와

PageImpl 이라는 객체로 반환하면 되고, 파라미터를 잘 입력해주면 된다.

실제 이 메서드를 사용하는 방법은, Pageable 인터페이스를 구현한 PageRequest 객체를 활용해서, page와 limit 설정을 해주면 된다.

PageRequest pageRequest = PageRequest.of(0,3);


위와 같은 Pageable을 상속하는 PageRequest 클래스를 만들어 파라미터로 전달해주면,

3개씩 나눴을 떄, 0페이지 데이터를 가져올 수 있다.

혹은 count query 는 따로 queryfactory로 fetchCount() 해서 구하고, 그냥 결과는 fetch()로 가져오는 방법이 있다. 기본적으로 조인이 들어가면 count쿼리가 복잡해지기 때문이다.

//count 쿼리와 분리한 예시

public Page<MemberDto> searchPageComplex (MemberSearchCondition condition, Pageable pageable){
            List<MemberTeamDto> content = queryFactory
                    .select(new QMemberTeamDto(
                            member.id,
                            member.username,
                            member.age,
                            team.id,
                            team.name))
                    .from(member)
                    .leftJoin(member.team, team)
                    .where(usernameEq(condition.getUsername()),
                            teamNameEq(condition.getTeamName()),
                            ageGoe(condition.getAgeGoe()),
                            ageLoe(condition.getAgeLoe()))
                    .offset(pageable.getOffset())
                    .limit(pageable.getPageSize())
                    .fetch();
      
            long total = queryFactory
                    .select(member)
                    .from(member)
                    .leftJoin(member.team, team)
                    .where(usernameEq(condition.getUsername()),
                            teamNameEq(condition.getTeamName()),
                            ageGoe(condition.getAgeGoe()),
                            ageLoe(condition.getAgeLoe()))
                    .fetchCount();
      
            return new PageImpl<>(content, pageable, total);
}