JPA
QueryDSL 페이징에 QuerydslPredicateExecutor 활용하기
Junuuu
2023. 10. 3. 00:01
728x90
QuerydslPredicateExecutor란?
Predicate 인스턴스를 실행할 수 있도록 spring data에서 지원하는 인터페이스입니다.
반환값들을 보면 Page<T>로 Predicate를 통해 페이징 된 결과를 받을 수 있습니다.
인터페이스의 네이밍을 보았을 때 Predicate를 기반으로 실행한다!라고 이해할 수 있습니다.
Predicate란?
Predicate를 직역하면 서술어라는 의미를 가집니다.
간단하게는 where 절에 들어가는 조건문을 뜻합니다.
BooleanBuilder, BooleanExpression이 Predicate 인터페이스를 구현하고 있습니다.
사용법
QuerydslPredicateExecutor 인터페이스 상속받기
@Repository
interface DeliveryJpaRepository : JpaRepository<DeliveryJpaEntity, UUID>,
CustomDeliveryJpaRepository, QuerydslPredicateExecutor<DeliveryJpaEntity> {
}
Adapter 부분 구현
fun loadNeedToReadyDeliveries(page: Int, size: Int, productId: Long?): Page<Delivery> {
val booleanExpression = generateLoadNeedToReadyDeliveriesPredicate(productId)
val pageable = PageRequest.of(page - 1, size, Sort.by("expectedDeliveryAt"))
return deliveryJpaRepository.findAll(booleanExpression, pageable)
.map { it.toDomainEntity() }
}
private fun generateLoadNeedToReadyDeliveriesPredicate(productId: Long?): Predicate {
val qDelivery: QDeliveryJpaEntity = QDeliveryJpaEntity.deliveryJpaEntity
return qDelivery.deliveryStatus
.eq(DeliveryStatus.WAITING)
.and(qDelivery.expectedDeliveryAt.isNotNull)
.and(productId(productId))
}
private fun productId(productId: Long?): BooleanExpression?{
val qDelivery: QDeliveryJpaEntity = QDeliveryJpaEntity.deliveryJpaEntity
if(productId == null){
return null
}
return qDelivery.productId.eq(productId)
}
booleanExpression을 활용하여 쿼리를 구성합니다, 이때 동적쿼리를 활용할 수 있습니다.
이후에는 page, size를 기반으로 Pageable 객체를 만들어냅니다
이후에는 간편하게 findAll을 사용하여 booleanExpression, pageable 객체를 넘겨주고, domainEntity로 반환하여 Service로 던져줍니다.
사용해 보면서 느낀 장점
- Predicate와 Pageable 객체만 넘기면 손쉽게 페이징 구현이 가능하다.
사용해 보면서 느낀 단점 (Predicate만 넘길 수 있음)
- group by 불가능
- join 불가능
즉, 조금 복잡한 케이스에 사용할 수 없다.
이런 경우에는 순수하게 쿼리를 작성하는 방법을 선택했다.
참고자료
http://querydsl.com/static/querydsl/3.7.2/reference/ko-KR/html/ch03.html