스프링/QueryDsl

[QueryDsl] 동적쿼리짜기

nomoreFt 2022. 3. 11. 22:56

QueryDsl의 동적 쿼리를 해결하는 방식

기본적으로 쿼리를 동적으로 사용한다는 의미는

파라미터의 값이 Null이냐 아니냐에 따라 동적으로 쿼리가 작성이 되는게 목적이다.
ex) 검색조건에서 많이 사용되는 것들`

 

1.BooleanBuilder 사용하기
2.where절에 다중 파라미터 사용하기


BooleanBuilder 사용

package com.querydsl.core BooleanBuilder 사용한다.

BooleanBuilder는 두개의 생성자를 가지고 있다.

최초 선언에 Predicate를 선언할 수 있는데, 생성하면서 null이면 안되는

Param들을 미리 선언해주면 된다.

    /**
     * Create an empty BooleanBuilder
     */
    public BooleanBuilder() {  }

    /**
     * Create a BooleanBuilder with the given initial value
     *
     * @param initial initial value
     */
    public BooleanBuilder(Predicate initial) {
        predicate = (Predicate) ExpressionUtils.extract(initial);
    }
 @Test
    public void dynamicQuery_BooleanBuilder() throws Exception {
        String usernameParam = "member1";
        Integer ageParam = 10;

       List<Member> result =  searchMember1(usernameParam, ageParam);
       assertThat(result.size()).isEqualTo(1);
    }

    private List<Member> searchMember1(String usernameParam, Integer ageParam) {

*******************************************************************************
       //1번. default Builder 생성으로 구현
        BooleanBuilder builder = new BooleanBuilder();
        if(usernameParam != null){
            builder.and(member.username.eq(usernameParam));
        }
        if(ageParam != null){
            builder.and(member.age.eq(ageParam));
        }
*********************************************************************************

*********************************************************************************
        //2번. Builder 초기값 삽입으로 구현 (member.username이 필수값인 경우)
        BooleanBuilder builder = new BooleanBuilder(member.username.eq("member1"));
        if(ageParam != null){
        builder.and(member.age.eq(ageParam));
        }
**********************************************************************************


        return queryFactory.selectFrom(member)
                .where(builder)
                .fetch();

    }
  • 💥builder도 and, or 등 추가 where 연산이 가능하다.

💫동적쿼리 where 다중 파라미터로 처리하기

앞서서

장점

  • Main query를 깔끔하게 유지하고, 명시성이 좋다.
  • BooleanExpression을 반환하여 새로운 조건들을 조합해서 사용할 수 있다. ex) 나이가 40이상, 이름 xx는 이벤트 대상자
  • 재사용성이 좋다.

BooleanExpression은 queryDsl에서 Predicate를 구현한 구현체이다

public abstract class BooleanExpression extends LiteralExpression<Boolean> implements Predicate

where절 안에 들어갈 true,false 값을 param에 따라 메서드로 추출하여 제작한다.

  • 📀 queryFactory의 where절에서 null이 들어가면 자동으로 skip으로 간주하기 때문에 동적 쿼리가 가능하다.
ex)  return queryFactory
        .selectFrom(member)
        .where(null, ageEq(ageParam))
        .fetch();
  • 위 상황에서는 age만 같은지 체크함

기본 코드

    @Test
    public void dynamicQuery_WhereParam() throws Exception {
        String usernameParam = "member1";
        Integer ageParam = null;

        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)) //where 절에 메서드를 제작해 동작. (Predicate만 받으면 된다)
        *******************************************************************************
                .fetch();
    }

where Param별 조건 메서드 생성

    private BooleanExpression ageEq(Integer ageParam) {
        return ageParam != null ? member.age.eq(ageParam) : null;
    }

    private BooleanExpression usernameEq(String usernameParam) {
        return usernameParam != null ? member.username.eq(usernameParam) : null;
    }
  • null은 skip하는 queryFactory의 where 조건절의 특성을 이용해 그냥 null을 리턴한다.

이 true,false만 지켜주면 어떤 메서드든 조합하여 만들 수 있다.

  private BooleanExpression allEq(String usernameParam, Integer ageParam){
        return usernameEq(usernameParam).and(ageEq(ageParam));
    }
  • usernameEq + ageEq를 조합해서 allEq를 만든 모습
    private List<Member> searchMember3(String usernameParam, Integer ageParam) {
        return queryFactory
                .selectFrom(member)
                .where(allEq(usernameParam,ageParam))
                .fetch();
    }
  • 극한으로 깔끔해졌다.