JPA

QueryDSL으로 동적쿼리 작성하기

Junuuu 2023. 9. 17. 00:01
728x90

개요

조회쿼리를 작성해야 하는데 다음과 같은 요구사항이 있었습니다.

  • 날짜를 저장하는 A칼럼, B칼럼이 존재한다.
  • "A칼럼 조회", "B칼럼 조회"와 같은 Client의 입력으로 A칼럼 또는 B칼럼에 대해 특정기간에 해당하는 Entity를 조회한다.

동적 조건에 따라 2가지 케이스를 쿼리해야 합니다.

  • A칼럼 조회가 들어오면 where 절에 A필드를 특정기간에 조회하는 쿼리
  • B칼럼 조회가 들어오면 where 절에 B필드를 특정기간에 조회하는 쿼리

 

A칼럼 조회가 들어오면 where 절에 A필드를 특정기간에 조회하는 쿼리예시

select *
from my_table
WHERE A = BETWEEN 조회시작시간 AND 조회끝시간

 

B칼럼 조회가 들어오면 where 절에 B필드를 특정기간에 조회하는 쿼리

select *
from my_table
WHERE B = BETWEEN 조회시작시간 AND 조회끝시간

 

QueryDSL 활용

override fun selectDeliveryInfos(condition: Condition): List<DeliveryJpaEntity> {
    val delivery: QDeliveryJpaEntity = QDeliveryJpaEntity.deliveryJpaEntity
    return jpaQueryFactory.select(delivery)
      .where(betweenDateConditionType(condition))
      .fetch()
  }

private fun betweenDateConditionType(condition: Condition): BooleanExpression {
    val delivery: QDeliveryJpaEntity = QDeliveryJpaEntity.deliveryJpaEntity
    val dateType = when (condition.dateConditionType) {
      DateConditionType.INVOICE_REGISTERED_DATE -> delivery.invoiceRegisteredAt
      DateConditionType.ADMIN_CHECK_DATE -> throw UnsupportedOperationException("아직 미구현") 
      DateConditionType.DELIVERY_COMPLETE_DATE -> throw UnsupportedOperationException("아직 미구현")
    }
    return dateType.between(condition.startDate, condition.endDate)
  }

 

이때 QueryDSL의 BooleanExpression을 활용하여 해결할 수 있습니다.

BooleanExpression은 where에서 사용할 수 있으며 null이 파라미터로 올 경우 조건문에서 제외합니다.

 

위의 쿼리문에서는 null은 직접적으로 활용하진 않았지만 이를 활용하여 송장번호가 등록된 날짜, 관리자가 확인한 날짜, 배송이 완료된 날짜로 WHERE 절을 만들어낼 수 있습니다.

 

테스트

@Test
@Sql("classpath:delivery.sql")
fun `배송처리일-기간조회(7월1일~8월20일) 수행하면 2개의 배송정보가 조회되어야 한다`(){
  val condition = Condition(
    dateConditionType = DateConditionType.INVOICE_REGISTERED_DATE,
    startDate = LocalDateTime.of(2023,7,1,0,0,0).toInstant(ZoneOffset.UTC),
    endDate = LocalDateTime.of(2023,8,20,23,59,59).toInstant(ZoneOffset.UTC),
  )
  
  val result = deliveryPersistenceAdapter.loadBy(condition = condition)

  result.deliveries.size shouldBe 2
}

임의로 N개의 데이터를 세팅하고 여기서 7월 10일, 8월 10일에만 invoiceRegisteeredAt 필드에 날짜를 지정하였습니다.

이후 테스트를 수행하면 N개의 데이터중 2개의 데이터만 조회되는 것을 확인할 수 있습니다.

반면에 해당하지 않는 과거의 날짜로 startDate, endDate를 설정하면 0개의 데이터가 조회됩니다.

 

 

 

참고자료

http://querydsl.com/static/querydsl/3.4.1/reference/ko-KR/html/ch03.html

https://jojoldu.tistory.com/394