동적 쿼리 사용 시 where 절 안에서 사용할 메소드들을 계속해서 만들다 보니
BooleanExpression(Predicate)을 만드는 코드의 양이 계속 커지고
매번 null 처리를 해주는 과정이 반복되서
이것마저 귀찮다고 느껴져 유틸 클래스를 만들어 보았습니다.
유틸 클래스 샘플 코드는 아래와 같습니다.
public class DynamicQueryUtils {
public static <T> BooleanExpression eq(SimpleExpression<T> left, T right) {
return right == null ? null : left.eq(right);
}
public static <T extends Number & Comparable<?>> BooleanExpression loe(NumberExpression<T> left, T right) {
return right == null ? null : left.loe(right);
}
public static <T extends Number & Comparable<?>> BooleanExpression goe(NumberExpression<T> left, T right) {
return right == null ? null : left.goe(right);
}
}
위와 같이 유틸 클래스에서 null을 확인해주는 메소드를 한번 만든 뒤 부터는
Repository에서 쿼리를 작성할 때 더 이상 null 처리를 신경 쓰지 않고 코드를 짤 수 있었습니다.
public List<MemberTeamDto> searchMember(MemberSearchCondition condition) {
return query.select(new QMemberTeamDto(member.id, member.username, member.age, team.id, team.name))
.from(member)
.join(member.team, team)
.where(
eq(member.username, condition.getUsername( )),
eq(team.name, condition.getTeamName( )),
goe(member.age, condition.getAgeGoe( )),
loe(member.age, condition.getAgeLoe( ))
)
.fetch( );
}
실제로 member를 검색하는 메소드를 변경해보았는데
static import를 활용하면 where 절 내부도 깔끔하게 만들 수 있고
BooleanBuilder를 사용하거나 usernameEq과 같은 추가적인 메소드를 만들지 않고도
동적 쿼리를 만들 수 있었습니다.
또, 기존 메소드를 이용하면 강력하게 활용할 수 있던 메소드 체이닝 기능도
유틸 클래스에서 비슷하게 제공하여 BooleanExpression(Predicate)을 열거하면
조건들을 조합할 수 있는 메소드를 만들었습니다.
public class DynamicQueryUtils {
public static Predicate conditions(Predicate... predicates) {
BooleanBuilder condition = new BooleanBuilder( );
Arrays.stream(predicates).filter(Objects::nonNull).forEach(condition::and);
return condition.getValue( );
}
}
private Predicate isValid(MemberSearchCondition condition) {
return conditions(
eq(member.username, condition.getUsername( )),
eq(team.name, condition.getTeamName( )),
goe(member.age, condition.getAgeGoe( )),
loe(member.age, condition.getAgeLoe( ))
);
}
이런 식으로 유틸 클래스를 한 번 만들고나니 Repository 계층을 작성하는 시점부터는
null을 신경쓰지 않고 코드를 작성할 수 있게 되더라구요.
Querydsl에서 혹은 서드파티 라이브러리에서 제공해 줄 것 같기도 한데
Querydsl 생태계를 잘 몰라 아직 찾지는 못하고 있는 상황입니다.
이런 방식으로 쿼리를 생성하는 건 어떨까요?
안녕하세요. in M님
아주 좋은 생각입니다^^
저도 코드를 참고해야겠네요 ㅎㅎ
공유 감사합니다.
답글