Skip to content

동적쿼리

Querydsl에서 동적인 쿼리를 생성해보자.

동적쿼리를 작성하는 방법은

1. BooleanBuilder를 작성하는 방법
2. Where 절과 Predicate를 이용하는 방법
3. Where 절과 피라미터로 Predicate 를 상속한 BooleanExpression을 사용하는 방법

총 세가지가 있다.

그렇다면 세가지 방법을 모두 비교해보자.

모든 코드에서 MemberSearchCondition를 파라미터로 받아 username, teamName, ageGoe, ageLoe를 조건으로 걸어 조회하고, 값이 null인경우 where절에 적용하지 않도록 했다.

@Getter
@NoArgsConstructor
public class MemberSearchCondition {
private String username;
private String teamName;
private Integer ageGoe;
private Integer ageLoe;
}

1. BooleanBuilder

public List<MemberTeamDto> searchByBuilder(MemberSearchCondition condition){
BooleanBuilder builder = new BooleanBuilder();
if (hasText(condition.getUsername())) {
builder.and(member.username.eq(condition.getUsername()));
}
if(hasText(condition.getTeamName())){
builder.and(team.name.eq(condition.getTeamName()));
}
if(condition.getAgeGoe() != null) {
builder.and(member.age.goe(condition.getAgeGoe()));
}
if(condition.getAgeLoe() != null){
builder.and(member.age.loe(condition.getAgeLoe()));
}
return queryFactory
.select(new QMemberTeamDto(
member.id.as("memberId"),
member.username,
member.age,
team.id.as("teamId"),
team.name.as("teamName")
))
.from(member)
.leftJoin(member.team, team)
.where(builder)
.fetch();
}

if문으로 해당 필드에 값이 존재하는지 확인한 후에 필요한 부분을 BooleanBuilder에 추가하여 조회하는 방법이다. 사실 이 방법도 아래의 방법과 똑같이 BooleanExpression을 사용하고 있지만, BooleanBuilder에 한번에 모은다음 조건에 넣는다는 점이 다르다. Where문의 조건들을 한눈에 보기 어렵고, 어떤 쿼리가 나가는지 예측하기 힘들다는 단점이 있다.

2. Where 절과 BooleanExpression

public List<MemberTeamDto> searchByBooleanExpression(MemberSearchCondition condition){
return queryFactory
.select(new QMemberTeamDto(
member.id.as("memberId"),
member.username,
member.age,
team.id.as("teamId"),
team.name.as("teamName")
))
.from(member)
.leftJoin(member.team, team)
.where(
usernameEq(condition.getUsername()),
teamNameEq(condition.getTeamName()),
ageGoe(condition.getAgeGoe()),
ageLoe(condition.getAgeLoe())
)
.fetch();
}
private BooleanExpression usernameEq(String username) {
return hasText(username) ? member.username.eq(username) : null;
}
private BooleanExpression teamNameEq(String teamName) {
return hasText(teamName) ? team.name.eq(teamName) : null;
}
private BooleanExpression ageGoe(Integer ageGoe) {
return ageGoe != null ? member.age.goe(ageGoe) : null;
}
private BooleanExpression ageLoe(Integer ageLoe) {
return ageLoe != null ? member.age.loe(ageLoe) : null;
}
private BooleanExpression ageBetween(Integer ageLoe, Integer ageGoe) {
return ageLoe(ageLoe).and(ageGoe(ageGoe));
}

BooleanExpression 은 and 와 or 같은 메소드들을 이용해서 BooleanExpression 을 조합해서 새로운 BooleanExpression 을 만들 수 있기 때문에 재사용성이 높고, null일경우 Where 절에서 자동으로 무시되기 때문에 안전하다는 장점이 있다. (하지만 모든 조건이 null일 경우에는 장애가 발생할 수 있으니 주의해야한다.)

그렇기 때문에 동적 쿼리를 써야할때는 BooleanExpression을 사용하는 것이 좋다고 한다.

출처:
[우아콘2020] 수십억건에서 QUERYDSL 사용하기 https://www.youtube.com/watch?v=zMAX7g6rO_Y&t=656s