Programing/Spring Boot

코틀린 스프링부트 Querydsl 사용 예제

딩코딩 2023. 7. 3. 23:20

우선 Querydsl을 사용하기 위해서는 인터페이스를 만들고, 구현체를 만들고, Repository에 상속한다

 

1. Repository (SpringDataJpa, Querydsl 2개를 상속받았다)

@Repository
interface MemberRepository : JpaRepository<Member, Long>, MemberRepositoryCustom {
}

 

2. 인터페이스 

interface MemberRepositoryCustom {
    fun search(condition: MemberSearchCondition): List<MemberTeamDto>
    fun searchPageSimle(condition: MemberSearchCondition, pageable: Pageable): Page<MemberTeamDto>
    fun searchPageComplex(condition: MemberSearchCondition, pageable: Pageable): Page<MemberTeamDto>
}

 

3. 구현부

//MemberRepositoryCustomImpl : MemberRepositoryCustom
override fun searchPageSimle(condition: MemberSearchCondition, pageable: Pageable): Page<MemberTeamDto> {

    //페이징쿼리
    val content = queryFactory
            .select(QMemberTeamDto(
                    member.id.`as`("memberId"),
                    member.username,
                    member.age,
                    team.id.`as`("teamId"),
                    team.name.`as`("teamName")
            ))
            .from(member)
            .leftJoin(member.team, team)
            .where(
                    usernameEq(condition.username),
                    teamNameEq(condition.teamName),
                    ageGoeEq(condition.ageGoe),
                    ageLoeEq(condition.ageLoe)
            )
            .offset(pageable.offset)
            .limit(pageable.pageSize)
            .fetch()

    //카운트 쿼리
    val totalSize = queryFactory
            .selectFrom(member)
            .leftJoin(member.team, team)
            .where(
                    usernameEq(condition.username),
                    teamNameEq(condition.teamName),
                    ageGoeEq(condition.ageGoe),
                    ageLoeEq(condition.ageLoe)
            )
            .fetch().size
    return PageImpl(content, pageable, totalSize)
}

//`PageableExecutionUtils.getPage()`로 최적화

override fun searchPage_최적화(condition: MemberSearchCondition, pageable: Pageable): Page<MemberTeamDto> {
    val content = queryFactory
            .select(QMemberTeamDto(
                    member.id.`as`("memberId"),
                    member.username,
                    member.age,
                    team.id.`as`("teamId"),
                    team.name.`as`("teamName")
            ))
            .from(member)
            .leftJoin(member.team, team)
            .where(
                    usernameEq(condition.username),
                    teamNameEq(condition.teamName),
                    ageGoeEq(condition.ageGoe),
                    ageLoeEq(condition.ageLoe)
            )
            .offset(pageable.offset)
            .limit(pageable.pageSize)
            .fetch()

    val countQuery = queryFactory
            .selectFrom(member)
            .leftJoin(member.team, team)
            .where(
                    usernameEq(condition.username),
                    teamNameEq(condition.teamName),
                    ageGoeEq(condition.ageGoe),
                    ageLoeEq(condition.ageLoe)
            )

    return PageableExecutionUtils.getPage(content, pageable, { countQuery.fetch().size })
}

- 스프링 데이터 라이브러리가 제공
- count 쿼리가 생략 가능한 경우 생략해서 처리
    - 페이지 시작이면서 컨텐츠 사이즈가 페이지 사이즈보다 작을 때
    - 마지막 페이지 일 때 (offset + 컨텐츠 사이즈를 더해서 전체 사이즈 구함)

::: aside 💡

Controller에서 사용

:::

@RestController
@RequiredArgsConstructor
class MemberController(private val memberRepository: MemberRepository) {

    @GetMapping("/v2/members")
    fun searchMemberV2(condition: MemberSearchCondition, pageable: Pageable): Page<MemberTeamDto> {
        return memberRepository.searchPageComplex(condition, pageable)
    }

}