ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • QueryDSL으로 동적쿼리 작성하기
    JPA 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

     

     

     

    댓글

Designed by Tistory.