[QueryDSL] 동적 쿼리 (BooleanExpression)
2022. 8. 28. 15:15ㆍLanguage`/JPA
QueryDSL은 SQL자체를 자바 코드로 작성하기 때문에 TypeSafe하고 컴파일 시점에 오류를 발견할 수 있다는 장점이 존재한다.
더불어서 QueryDSL의 가장 큰 장점 중 하나는 "동적 쿼리 생성의 편리함"이다
QueryDSL에서 where절에 동적 쿼리를 생성하기 위해서는 "BooleanExpression"을 활용하면 된다
BooleanExpression
BooleanExpression을 return하는 "동적 쿼리 전용 메소드"를 만들면 굉장히 편리하게 특정 조건에 따른 동적 쿼리를 작성할 수 있다
Integer ageUpper = 25;
String userNameContains = "nus1";
List<Member> fetch = query.selectFrom(member)
.where(member.age.goe(ageUpper).and(member.username.contains(userNameContains)))
.orderBy(member.age.asc())
.fetch();
for (Member member : fetch) {
System.out.println(member);
}
현재 이 쿼리는 where절에 그대로 각 값의 조건을 넣은 쿼리이다
여기서 만약에 age/username중 특정 조건만 넣고 싶다면 직접 where절을 변형시켜야 한다
하지만 BooleanExpression을 활용하면 직접 where절을 변형시키지 않아도 BooleanExpression의 동작 원리에 따라서 알아서 where절을 만들어준다
- BooleanExpression에서 "null"을 반환하게 된다면 where절에서 해당 조건은 제거된다
// BooleanExpression
private BooleanExpression goeAge(Integer age) {
if (age == null) {
return null;
}
return member.age.goe(age);
}
private BooleanExpression containsUsername(String username) {
if (username == null) {
return null;
}
return member.username.contains(username);
}
// Query
Integer ageUpper = 25;
String userNameContains = "nus1";
List<Member> fetch = query.selectFrom(member)
.where(
goeAge(ageUpper),
containsUsername(userNameContains)
)
.orderBy(member.age.asc())
.fetch();
for (Member member : fetch) {
System.out.println(member);
}
BooleanExpression를 사용하는 "where"절에서 콤마(,)의 의미는 각 조건을 연결하는 and()와 동일하다
여기서 만약 ageUpper를 null로 초기화한다면 어떤 쿼리가 날라갈지 살펴보자
// BooleanExpression
private BooleanExpression goeAge(Integer age) {
if (age == null) {
return null;
}
return member.age.goe(age);
}
private BooleanExpression containsUsername(String username) {
if (username == null) {
return null;
}
return member.username.contains(username);
}
// Query
Integer ageUpper = null; // age null
String userNameContains = "nus1";
List<Member> fetch = query.selectFrom(member)
.where(
goeAge(ageUpper),
containsUsername(userNameContains)
)
.orderBy(member.age.asc())
.fetch();
for (Member member : fetch) {
System.out.println(member);
}
BooleanExpression에 따라서 동적으로 where절의 쿼리가 변형됨을 확인할 수 있다
BooleanExpression은 특정 조건에 대해서 문장으로 나열하지 않고 "의미있는 메소드"로 동적 조건을 결정하기 때문에 가독성도 더 뛰어나고 편리하다
물론 BooleanBuilder를 통해서 BooleanBuilder 내부적으로 모든 조건을 판단하고 where절에 builder하나만 넣어도 되긴하지만 가독성이 떨어지고 어떤 쿼리가 나갈지 예상하기 힘들기 때문에 BooleanBuilder보다는 "BooleanExpression"을 사용하는 것을 권장한다