본문 바로가기
JPA/Querydsl

Querydsl 08 - 동적 쿼리

by 킹차니 2022. 1. 20.

 

 

동적 쿼리를 해결하는 데에는 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를 바탕으로 정리하였습니다.