동적 쿼리를 해결하는 데에는 2가지 방식이 있다.
1. BooleanBuilder
2. Where 다중 파라미터 사용
1. BooleanBuilder
코드로 보자
@Test
void dynamicQuery_BooleanBuilder() {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember1(usernameParam, ageParam);
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();
}
searchMember1 메서드를 보면 만약 usernameCond가 null이 아니면 builder.and로 username조건을 추가하는 것을 볼 수 있다. age도 마찬가지이다.
위를 수행해보면 아래와 같은 쿼리가 나간다.
select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
where
member0_.username=?
and member0_.age=?
username과 age가 null이 아니기 때문에 where 절 뒤에 username과 age가 조건으로 붙게 된다. 하지만 만약 username이 null이라면 아래와 같은 쿼리가 나간다.
select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
where
member0_.age=?
where 절 뒤에 age만을 조건으로 가져오는 쿼리가 나간 것을 볼 수 있다.
2. Where 다중 파라미터 사용
바로 코드로 보자.
@Test
void dynamicQuery_whereParam() {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember2(usernameParam, ageParam);
assertThat(result.size()).isEqualTo(1);
}
private List<Member> searchMember2(String usernameParam, Integer ageParam) {
return queryFactory.selectFrom(member)
.where(usernameEq(usernameParam), ageEq(ageParam))//null이면 무시된다.
.fetch();
}
private BooleanExpression usernameEq(String usernameParam) {
if(usernameParam==null) return null;
else return member.username.eq(usernameParam);
}
private BooleanExpression ageEq(Integer ageParam) {
return ageParam == null ? null : member.age.eq(ageParam);
}
searchMember2의 where문을 보면 usernameEq(usernameParam)과 ageEq(ageParam)이 들어가는 것을 알 수 있다. where안에 Predicate 타입으로 넘어오는 파라미터들은 null이면 무시된다. 현재 usernameEq, ageEq메서드가 BooleanExpression을 반환하고 있는데, BooleanExpression은 Predicate를 implements한다.
위와 같은 방식의 장점:
1. 메서드를 다른 커리에서도 재활용 할 수 있다.
2. 쿼리 자체의 가독성이 높아진다.
usernameEq와 ageEq를 조합하여 아래와 같이 사용할 수 있다.
@Test
void dynamicQuery_whereParam() {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember2(usernameParam, ageParam);
assertThat(result.size()).isEqualTo(1);
}
private List<Member> searchMember2(String usernameParam, Integer ageParam) {
return queryFactory.selectFrom(member)
.where(allEq(usernameParam,ageParam))/*allEq사용*/
.fetch();
}
private BooleanExpression allEq(String usernameParam, Integer ageParam) {
return usernameEq(usernameParam).and(ageEq(ageParam));
}
private BooleanExpression usernameEq(String usernameParam) {
if(usernameParam==null) return null;
else return member.username.eq(usernameParam);
}
private BooleanExpression ageEq(Integer ageParam) {
return ageParam == null ? null : member.age.eq(ageParam);
}
위와 같은 방법을 잘 사용하면 광고와 관련된 서비를 위해 광고 상태(IsValid)와 날짜(In)를 잘 조합하여 isServiceable이라는 메서드를 만들어낼 수 있다.
김영한님의 인프런 강의와 PDF를 바탕으로 정리하였습니다.
'JPA > Querydsl' 카테고리의 다른 글
Querydsl 10 - SQL function 호출하기 (0) | 2022.01.20 |
---|---|
Querydsl 09 - 수정, 삭제 배치 쿼리 (0) | 2022.01.20 |
Querydsl 07 - 프로젝션과 결과반환 (0) | 2022.01.19 |
Querydsl 06 - Case문, 상수 문자 더하기 (0) | 2022.01.18 |
Querydsl 05 - 서브쿼리 (0) | 2022.01.18 |