QueryParameter - Sort
/search?category=book&price=1000&page=0&size=10&sort=id,asc&sort=price,desc
정렬 조건은 queryparameter를 통해 주로 전달합니다.
ex) sort=id,asc
- 위 코드는 id 값을 기준으로 오름차순 정렬을 의미합니다.
복수 개의 정렬은 단일 조건이 여러 번 전달받는 것과 같습니다.
ex) sort=id,asc&sort=price,desc
querydsl에서 정렬 조건을 주기 위해 2가지 방법이 있습니다.
QEntity.field.asc() / QEntity.field.desc()
첫 번째는 정적인 방법으로 QEntity.field.asc() / QEntity.field.desc() 방법이 있습니다.
return jpaQueryFactory.selectFrom(product)
.offset(offset)
.limit(pageSize)
.orderBy(product.price.asc())
.fetch();
두 번째 방법은 동적으로 정렬을 작성하는 방법입니다.
OrderSpecifier - 동적 정렬
QueryParameter를 통해 sort=field,asc(desc) 를 전달받아 Orderspecifier 객체를 생성하여 정렬 조건에 추가해 줍니다.
jpaQueryFactory
.select(Projections.fields(ProductResponse.class,
product.name,
product.price,
product.category))
.from(product)
.where(priceGoe(productVO.price()),
categoryEq(productVO.category()))
.orderBy(getOrderSpecifiers(pageable.getSort())) // 생성한 OrderSpecifier 적용
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
//===//
private OrderSpecifier<?>[] getOrderSpecifiers(Sort sort) {
List<OrderSpecifier<?>> orders = new ArrayList<>();
for (Sort.Order order : sort) {
Order direction = order.isAscending() ? Order.ASC : Order.DESC;
PathBuilder<Product> pathBuilder = new PathBuilder<>(product.getType(), product.getMetadata());
orders.add(new OrderSpecifier<>(direction, pathBuilder.getString(property)));
}
return orders.toArray(new OrderSpecifier[0]);
}
Sort는 Controller에서 받은 정렬 정보를 가지고 있습니다.
이를 Controller에서 Pageable 객체를 만들어 Repository에서 사용합니다.
정렬 조건이 여러 개인 경우 리스트가 아닌 배열을 통해 설정할 수 있습니다.
먼저, Sort에 담긴 조건을 List<OrderSpecifier> 자료형에 담습니다.
마지막에, 해당 리스트를 toArray()를 통해 배열로 변환하여 orderBy() 절에 사용합니다.
orders.toArray(new OrderSpecifier[0]) 왜 빈 배열을 넣는지?
JVM을 통해 적절한 크기로 배열을 초기화하기 위해서
toArray(T[] a) 메서드 동작 원리
- 전달된 배열의 크기가 리스트의 크기보다 크거나 같다면, 그 배열을 사용하여 리스트의 요소들을 채우고, 남은 자리를 null로 초기화합니다.
- 전달된 배열의 크기가 리스트의 크기보다 작다면, 리스트의 크기에 맞는 새로운 배열을 생성하고, 그 배열을 반환합니다.
(2번째 원리를 통해 배열로 변환하기 위해 빈 배열을 전달합니다.)
제네릭 배열 생성 문제 해결
- Java에서는 제네릭 타입의 배열을 직접 생성하는 것이 허용되지 않습니다. 이를 해결하기 위해 빈 배열을 전달하여 타입 안정성을 유지하면서 배열을 반환할 수 있도록 합니다.
for (Sort.Order order : sort) {
Order direction = order.isAscending() ? Order.ASC : Order.DESC;
PathBuilder<Product> pathBuilder = new PathBuilder<>(product.getType(), product.getMetadata());
orders.add(new OrderSpecifier<>(direction, pathBuilder.getString(property)));
}
정렬 조건 초기화 하는 과정
- 정렬할 방향을 정하기
- Entity fileld 지정하기
OrderSpeifier에는 일반 필드 변수가 아니라 Expression으로 QEntity field의 path를 지정해야 합니다.
이를 위해 PathBuilder를 사용하여 적용하고자 하는 엔티티의 필드를 지정합니다.
PathBuilder
매개변수로 Class<?>와 PathMetadata를 받습니다.
이에 대해 QEntity.getType(), QEntity.getMeteData()를 인자로 전달하여 pathBuilder를 생성합니다.
생성한 pathBuilder를 통해 getString() 메서드를 통해 정렬할 인자를 동적으로 설정해 줍니다.
'Spring Framework > QueryDSL' 카테고리의 다른 글
Spring MongoDB 환경 QueryDSL 설정하기 (0) | 2025.01.02 |
---|---|
Querydsl 날짜 연산 문제 해결 : Interval 예약어 미지원 - Java 날짜 객체를 사용하기 (1) | 2024.11.15 |
[Querydsl] JPAExpressions를 활용한 Querydsl 서브쿼리 작성 방법 (0) | 2024.10.17 |
[Querydsl] QueryDSL @QueryProjection 프로젝션 활용법 : DTO, Bean, Field, Constructor 사용법 (0) | 2024.09.16 |
[QueryDsl] QueryDsl groupBy 여러 개 적용하기 (0) | 2024.08.10 |