동적쿼리 사용 2가지 방법
동적 쿼리 사용을 위해서는 2가지 방법이 있습니다.
- BooleanBuilder
- Where 다중 파라미터 사용
BooleanBuilder
where절에 BooleanBuilder를 넣는 방식입니다. and 혹은 or을 사용할 수 있습니다. 아래는 username과 age를 동적 쿼리로 조회합니다.
where 절의 핵심 코드는 아래와 같습니다.
...
.where(builder)
...
@Test
public void BooleanBuilderQuery() {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember1(usernameParam, ageParam);
Assertions.assertThat(result.size()).isEqualTo(1);
}
private List<Member> searchMember1(String usernameCond, Integer ageCond) {
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();
}
where절에는 username과 age 모두 검색조건에 들어가 있습니다.
age를 null로 바꾸고 쿼리문을 짜봅니다.
Integer ageParam = null;
위의 where 조건에는 age가 포함되어 있었으나, 이제 age가 포함되지 않습니다. 동적으로 null이므로 빠졌습니다.
참고로 방어코드를 짠다는 전제하에, BooleanBuilder에 초기값을 넣을 수도 있습니다.
BooleanBuilder builder = new BooleanBuilder(member.username.eq(usernameCond));
Where 다중 파라미터 사용
운영에서는 첫번째 BooleanBuilder보다는 Where 다중 파라미터 사용이 굉장히 편리합니다. where에서 좀 더 직관적으로 코드를 짤 수 있고 재사용도 가능합니다.
BooleanExpression을 리턴하는 usernameEq(String usernameCond), ageEq(Integer ageCond) 메서드를 만들어서 이름과나이를 검사할 수 있습니다.
where 절의 핵심 코드는 아래와 같습니다.
...
.where(usernameEq(usernameCond), ageEq(ageCond))
...
전체 코드는 아래와 같습니다.
@Test
public void 동적쿼리_WhereParam() throws Exception {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember2(usernameParam, ageParam);
Assertions.assertThat(result.size()).isEqualTo(1);
}
private List<Member> searchMember2(String usernameCond, Integer ageCond) {
return queryFactory
.selectFrom(member)
.where(usernameEq(usernameCond), ageEq(ageCond))
.fetch();
}
private BooleanExpression usernameEq(String usernameCond) {
return usernameCond != null ? member.username.eq(usernameCond) : null;
}
private BooleanExpression ageEq(Integer ageCond) {
return ageCond != null ? member.age.eq(ageCond) : null;
}
Where 다중 파라미터 방식은 첫번째 방식 BooleanBuilder와 같은 JPQL 쿼리문이 동작합니다.
만약, usernameEq와 ageEq를 한번에 사용하고 싶다면 다음처럼 allEq() 함수를 만들어서 합칠 수 있습니다. BooleanExpression을 and로 연결하여 반환합니다.
@Test
public void 동적쿼리_WhereParam() throws Exception {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember2(usernameParam, ageParam);
Assertions.assertThat(result.size()).isEqualTo(1);
}
private List<Member> searchMember2(String usernameCond, Integer ageCond) {
return queryFactory
.selectFrom(member)
//.where(usernameEq(usernameCond), ageEq(ageCond))
.where(allEq(usernameCond, ageCond)
.fetch();
}
private BooleanExpression usernameEq(String usernameCond) {
return usernameCond != null ? member.username.eq(usernameCond) : null;
}
private BooleanExpression ageEq(Integer ageCond) {
return ageCond != null ? member.age.eq(ageCond) : null;
}
private BooleanExpression allEq(String usernameCond, Integer ageCond) {
return usernameEq(usernameCond).and(ageEq(ageCond));
}
BooleanExpression이 composite할 수 있는 특징을 이용해서 여러상황을 만들 수 있고, 재사용이 가능합니다. 예를들어 광고 아이디와 날짜를 이용해 광고 가능한 상태인가를 판단하는 문법을 다음과 같이 만들 수 있습니다.
//핵심코드
...
where(isServiceable(id, date))
...
private BooleanExpressions isServiceable(Integer id, String date) {
return isValid(id).and(DateBetweenIn(date);
}
동적쿼리를 검사할 때, 간단할 때 3항연산자를 쓰지만, if문으로 만들 수도 있습니다.
//삼항 연산자
private BooleanExpression usernameEq(String usernameCond) {
return usernameCond != null ? member.username.eq(usernameCond) : null;
}
//if,else
private BooleanExpression usernameEq(String usernameCond) {
if(usernameCond == null) return null;
return member.username.eq(usernameCond);
}
1,2번 방식을 비교해보겠습니다.
//1. BooleanBuilder
.where(builder);
//2. where 다중 파라미터 사용
.where(usernameEq(usernameCond), ageEq(ageCond));
BooleanBuilder 보다는 확실히 Where 다중 파라미터 사용이 where문을 봤을 때 좀 더 직관적으로 이해 할 수 있습니다. 또한 where 다중 파라미터 사용을 한다면 메서드들을 재활용할 수 있습니다.
물론, 동적쿼리인만큼 항상 null 체크에 주의해야 합니다.
* 출처
Inflearn : 실전! Querydsl 강의
'Spring > Querydsl' 카테고리의 다른 글
순수 JPA와 Querydsl (0) | 2022.02.13 |
---|---|
QueryDsl 수정, 삭제 (0) | 2022.02.13 |
QueryDsl 프로젝션 문법 (0) | 2022.02.13 |
QueryDsl 기본문법 (0) | 2022.02.12 |
JPA & JPQL & QueryDsl (0) | 2022.02.12 |