QueryDSL은 JPQL 생성및실행을 담당하는 프레임워크이다. 개발자(클라이언트)가 원하는 JPQL을 QueryDSL에게 요청하려면 적절한 조건을 '표현'(Expression)해야 한다. '표현'(Expression)이라고 말한 이유는 QueryDSL이 실제로 클라이언트가 원하는 JPQL을 Expression 인터페이스로 표현할 수 있는 환경을 제공하고 있기 때문이다.
표현은 데이터 타입에 따라 분류된다.
NumberExpression : avg, add, abs ...
BooleanExpression : and, or, isTrue, isFalse ...
StringExpression : concat, charAt, contains, append ...
DateExpression : dayOfMonth, dayOfWeek, dayOfYear ...
EnumExpression : ordinal ...
클라이언트가 상품의 평균 가격을 조회하는 JPQL 생성 및 실행을 원한다면 '조회된 상품의 평균 가격'을 표현해야 한다.
qProduct.price.avg() : '조회된 상품의 평균 가격'
NumberExpression은 avg메소드로 조회된 상품의 평균 가격을 '표현'한다. 이렇듯, 세부적인 표현은 데이터 타입에 따른 Expression 클래스에 정의된 메소드로 표현한다. 그렇다면 공통으로 사용되는 표현은 무엇이 있을까?
지난 포스팅에서는 LiteralExpression 클래스에 대해서 다루어 보았다. 이번 포스팅에서는 ComparableExpressionBase에 대해서 다루어 보겠다. ComparableExpressionBase은 비교를 표현하는 메소드를 담은 클래스로, 거의 모든 데이터 타입 Expression이 이를 상속하고 있다.
가장 기본이 되는 비교 표현은 ComparableExpressionBase 클래스에 담겨 있다.
- min, max
최대, 최소를 표현하는 메소드이다.
// min 메소드
queryFactory.select(qProduct.price.min()) // 표현 : 조회된 상품 중 최소 가격
.from(product)
.fetchOne();
// max 메소드
queryFactory.select(qProduct.price.max())// 표현 : 조회된 상품 중 최대 가격
.from(product)
.fetchOne();
- asc, desc
내림차순, 오름차순 정렬도 비교 표현 중 하나이다.
// asc 메소드
queryFactory.selectFrom(product)
.orderBy(product.price.asc()) // 표현 : 조회된 상품을 가격의 오름차순으로 정렬
.fetch();
// desc 메소드
queryFactory.selectFrom(product)
.orderBy(product.createdDate.desc()) // 표현 : 조회된 상품을 날짜 데이터의 내림차순으로 정렬
.fetch();
- coalesce
null 값인지 비교하여 null을 처리하는 표현도 있다.
// coalesce 메소드
queryFactory.select( product.salePrice.coalesce(product.regularPrice)). // null이면 regularPrice null이 아니면 salePrice
from(product)
.fetch();
할인가격이 null이면 정규가격이 조회되도록 표현하고 싶다면
product.salePrice.coalesce(product.regularPrice) 로 표현하면 된다.
여기까지는 모두가 공통으로 사용하는 ComparableExpressionBase에 정의되어 있는 메소드이다.
NumberExpression을 제외하고 다른 데이터 타입의 Expression은 ComparableExpression 클래스를 상속하고 있다. 그렇다고 ComparableExpression에 정의된 메소드가 NumberExpression에 없는 것은 아니다. NumberExpression이 ComparableExpression을 상속하지 않을 뿐, ComparableExpression에 정의된 메소드는 NumberExpression에 정의되어 있다. ( 나중에 버전이 올라가면서 어떻게 통합될지는 모르겠다. )
- between
특정범위에 있는 값 여부를 비교할 때 사용하는 표현이다.
//between 메소드
queryFactory.selectFrom(sale)
.where(sale.saleDate.between(startDate, endDate)) // 표현 : 시작날짜와 종료날짜 사이에 있는 판매상품 조회
.fetch();
- loe, goe, lt, gt
값의 비교를 나타내는 표현을 담은 메소드이다.
member.age.goe(30) // 표현 : 회원의 나이가 30보다 크거나 같은가?
member.age.gt(30) // 표현 : 회원의 나이가 30보다 큰가?
member.age.loe(30) // 표현 : 회원의 나이가 30보다 작거나 같은가?
member.age.lt(30) // 표현 : 회원의 나이가 30보다 작은가?
- as
as는 alias로, 별칭을 줄 때 사용하는 표현이다.
queryFactory.select(
product.salePrice.coalesce(product.regularPrice).as("finalPrice") // 할인가와 정규가 중 null 여부로 결정된 가격을 finalPrice로 별칭
)
.from(product)
.fetch();
이렇듯 , 값의 비교는 모든 데이터 타입에 필요한 표현이므로, ComparableExpressionBase를 상속하고 재정의하여 각 데이터 타입에 맞는 비교와 관련된 표현을 제공하고 있다.
참고자료
'JPA > QueryDSL' 카테고리의 다른 글
[QueryDSL] 공통으로 사용하는 표현 - LiteralExpression (0) | 2023.08.07 |
---|---|
[QueryDSL] 결과조회 ( fetch ) (0) | 2023.08.07 |
[QueryDSL] 검색조건 ( where ) (0) | 2023.08.07 |
[QueryDSL] Expression( 표현 ) (0) | 2023.08.04 |
[QueryDSL] QueryDSL 동작원리(3) - fetch (0) | 2023.08.02 |