동적 쿼리
동적 쿼리는 애플리케이션에서 매우 흔하게 마주치는 요구 사항 중 하나다.
과거 자바 애플리케이션에서 쿼리를 동적으로 수정하는 것은 거의 불가능에 가까웠었다.
QueryDSL은 이러한 동적 쿼리를 처리하는 강력한 방법을 제공한다.
이번 글에서는 BooleanBuilder를 활용하여 동적 쿼리를 구성하는 방법을 알아보겠다.
방법1. BooleanBuilder를 통한 조건 구성
BooleanBuilder란?
BooleanBuilder는 QueryDSL에서 제공하는 조건을 동적으로 구성할 수 있는 편리한 클래스이다.
쿼리의 조건문(where 절)을 조건에 따라 유연하게 변경할 수 있게 해준다.
이를 통해 코드의 가독성을 유지하면서도 복잡한 조건 로직을 쉽게 구현할 수 있다.
동적 쿼리 구현 예제 다음은 BooleanBuilder를 사용하여 사용자 이름(username)과 나이(age) 조건에 따라 동적으로 쿼리를 구성하는 예제다.
사용자 이름 또는 나이 조건 중 하나만 주어져도 해당하는 조건에 맞는 데이터를 조회할 수 있다.
두 조건이 모두 주어지면, 두 조건을 모두 만족하는 데이터를 조회한다. 어떻게 그것이 가능한지 아래 코드로 알아보겠다.
private JPAQueryFactory queryFactory;
private List<Member> searchMember1(String usernameCond, Integer ageCond) {
QMember member = QMember.member;
BooleanBuilder builder = new BooleanBuilder();
if (usernameCond != null) {
builder.and(member.username.eq(usernameCond));
}
if (ageCond != null) {
builder.and(member.age.eq(ageCond));
}
return queryFactory
.selectFrom(member)
.where(builder)
.fetch();
}
BooleanBuilder는 조건문을 동적으로 구성할 때 사용되는 com.querydsl.core.BooleanBuilder 클래스의 인스턴스이다.
조건이 null이 아닐 때만 특정 조건을 추가하는 방식으로 작동하며, 이를 통해 코드의 가독성을 유지하면서 복잡한 조건 로직을 쉽게 구현할 수 있다.
방법2. ⭐️ Where 다중 파라미터 사용 ⭐️
QueryDSL의 또 다른 강력한 기능은 where 조건에 다중 파라미터를 사용할 수 있다.
이 방식은 조건의 조합을 더욱 유연하게 만들어준다.
Querydsl의 다중 파라미터의 가장 중요한 것은 where 절 내의 메서드가 null을 반환할 경우 자동으로 그 조건을 무시한다!
다중 조건의 동적 쿼리 예제 아래 코드는 usernameEq와 ageEq 조건을 allEq 메서드에서 조합하여 사용하는 방법을 보여준다.
이를 통해, 단일 조건으로도 재사용할 수 있고, 필요에 따라 조합하여 사용할 수 있다.
이는 QueryDSL에서 제공하는 BooleanExpression의 재사용성과 유연성을 극대화한다.
private List<Member> searchMember2(String usernameCond, Integer ageCond) {
return queryFactory
.selectFrom(member)
// .where(usernameEq(usernameCond), ageEq(ageCond))
.where(allEq(usernameCond, ageCond))
.fetch();
}
/**
* 아래와 같이 조합을 원할 경우, 조합을 원하는 원소 메서드들의 반환 값을
* Predicate가 아닌 BooleanExpression 으로 변경해야한다. (너무 중요⭐️)
* 기본 적으로 Where 문 매개변수 속 메서드의 반환 타입은 Predicate 이지만,
* 아래에서 조합하기 위해 BooleanExpression로 수정, 조합 가능 및 쿼리 정상 동작
* 단독으로 또는 조합해서 재사용 가능!
*
* ex)
* 광고 상태 isValid And 날짜가 IN 이여야함 = isServicable() 조합 및 재사용 가능
*/
private Predicate allEq(String usernameCond, Integer ageCond) {
return usernameEq(usernameCond).and(ageEq(ageCond));
}
private BooleanExpression usernameEq(String usernameCond) {
if (usernameCond != null) {
return member.username.eq(usernameCond);
}
return null;
}
private BooleanExpression ageEq(Integer ageCond) {
if (ageCond != null) {
return member.age.eq(ageCond);
}
return null;
}
위와 같이 사용할 때 메서드를 조합해서 사용할 수 있으며 이를 통해 쿼리를 재사용할 수 있다.
메서드로 추출시에 Predicate 타입으로 반환하는 메서드로 추출되는데, 이를 꼭 BooleanExpression으로 변경해야한다.
QueryDSL의 BooleanBuilder와 where 다중 파라미터 사용하면 동적 쿼리를 너무나도 쉽게 작성할 수 있다.
개인적으로 where의 다중 파라미터를 사용이 Querydsl의 꽃이라고 생각할 정도로 너무나도 중요하고 편리한 기능이다!
'JPA > QueryDSL' 카테고리의 다른 글
[QueryDSL] 7. QueryDSL의 Paging 처리 (Count Query 활용) (0) | 2023.12.07 |
---|---|
[QueryDSL] 5. QueryDSL의 프로젝션과 결과 반환, @QueryProjection (0) | 2023.12.06 |
[QueryDSL] 4. QueryDSL의 Join과 FetchJoin (0) | 2023.12.06 |
[QueryDSL] 3. 정렬과 페이징, SubQuery (0) | 2023.12.04 |
[QueryDSL] 2. QueryDSL 문법 VS JPQL 문법 비교 (0) | 2023.12.01 |