본문 바로가기

JPA

[Querydsl] 동적쿼리 작성하기

BooleanBuilder

BooleanBuilder 클래스를 이용하여 파라미터가 null이 아닌 경우에만 and() 메소드로 조건을 추가하고 where 절에 builder 객체를 기입하여 사용한다.

List<Member> result = searchMember1(usernameParam, ageParam);

...

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();
    }

Where 다중 파라미터

이 방법을 사용하면 리턴값이 null인 경우에는 where절에서는 무시된다.

BooleanBuilder를 사용한 방법보다 코드의 가독성이 좋고 사용한 메서드를 다른 쿼리에서도 사용할 수 있다는 장점이 있다.

List<Member> result = searchMember2(usernameParam, ageParam);

private List<Member> searchMember2(String usernameCond, Integer ageCond) {
    return queryFactory
            .selectFrom(member)
            .where(usernameEq(usernameCond), ageEq(ageCond))
            .fetch();
}

private Predicate usernameEq(String usernameCond) {
    return usernameCond != null ? member.username.eq(usernameCond) : null;
}

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

usernameEq() 메서드와  ageEq() 메서드를 조합하기

리턴 타입으로 BooleanExpression을 사용하면 여러가지 조건 메서드를 조합해서 사용할 수 있다.

List<Member> result = searchMember2(usernameParam, ageParam);

private List<Member> searchMember2(String usernameCond, Integer ageCond) {
    return queryFactory
            .selectFrom(member)
            .where(allEq(usernameCond, ageCond))
            .fetch();
}

private BooleanExpression usernameEq(String usernameCond) {
    return usernameCond != null ? member.username.eq(usernameCond) : null;
}

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

private BooleanExpression allEq(String usernameCond, Integer ageCond) {
	return usernameEq(usernameCond).and(ageEq(ageCond));
}

Spring Data JPA와 Querydsl 동적쿼리

MemberRepository

public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
    List<Member> findByUsername(String username);
}

MemberRepositoryCustom

public interface MemberRepositoryCustom {
    List<MemberTeamDto> search(MemberSearchCondition condition);
}

MemberRepositoryImpl

@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepositoryCustom {

    private final JPAQueryFactory queryFactory;

    @Override
    public List<MemberTeamDto> search(MemberSearchCondition condition) {
        return queryFactory
                .select(new QMemberTeamDto(
                        member.id.as("memberId"),
                        member.username,
                        member.age,
                        member.team.id.as("teamId"),
                        member.team.name.as("teamName")
                ))
                .from(member)
                .leftJoin(member.team, team)
                .where(
                        usernameEq(condition.getUsername()),
                        teamNameEq(condition.getTeamName()),
                        ageGoeEq(condition.getAgeGoe()),
                        ageLoeEq(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 ageGoeEq(Integer ageGoe) {
        return ageGoe != null ? member.age.goe(ageGoe) : null;
    }

    private BooleanExpression ageLoeEq(Integer ageLoe) {
        return ageLoe != null ? member.age.loe(ageLoe) : null;
    }
}

'JPA' 카테고리의 다른 글

[JPA] 벌크성 수정 쿼리  (0) 2023.04.02
[JPA] 고급 매핑 (상속 관계 매핑, @MappedSuperclass)  (0) 2023.03.13
[Querydsl] 프로젝션  (0) 2023.01.17
[Querydsl] Querydsl 적용하기  (0) 2023.01.15
[JPA] N + 1 문제와 해결방법  (0) 2022.10.19