ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Querydsl - where절을 이용한 동적 쿼리
    Spring/Querydsl 2022. 3. 25. 14:36
    728x90
    반응형

     

     

    where절을 이용한 동적 쿼리

     

     where절을 이용하여 동적 쿼리를 처리할 수 있다. where 조건에서 null 값이 들어오면 값은 무시되고 쿼리가 생성된다. 이러한 특성 때문에 다른 쿼리에서도 재활용이 가능한 장점이 있고, 또한 쿼리 자체의 가독성이 높아진다.  BooleanBuilder보다 사용하기 편하므로 이 방법을 권장한다.

     

    @Test
    public 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 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;
    }
        /* select
            member1 
        from
            Member member1 
        where
            member1.username = ?1 
            and member1.age = ?2 */ select
                member0_.member_id as member_id1_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=?

     

     

     위에서 코드를 보면 usernameEq과 ageEq 메서드를 이용하였다. 이 메서드들은 충분히 다른 쿼리에서도 충분히 쓸 수 있기 때문에 재사용성이 높아진다. 또한 생성한 메서드를 이용한 메서드를 만들 수 있다. 다음 예시를 보자.

     

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

     

     

     이처럼 usernameEq 메서드와 ageEq 메서드를 다음과 같이 재사용하여 하나의 다른 메서드를 생성할 수 있다. 


     

    참고
    위에 allEq 메서드는 null 체크를 하지 않았지만
    필수적으로 null 체크를 해줘야 한다.
    @DataJpaTest
    public class DynamicQueryTest {
    
        JPAQueryFactory queryFactory;
        @Autowired
        EntityManager em;
    
        @BeforeEach
        void init() {
            queryFactory = new JPAQueryFactory(em);
    
            em.persist(new Member("userA", 10, "ROLE_MASTER"));
            em.persist(new Member("userB", 20, "ROLE_ADMIN"));
            em.persist(new Member("userC", 30, "ROLE_USER"));
        }
    
        @Test
        void dynamicQuery() {
    
    //        Integer age = 10;
    //        String role = "ROLE_MASTER";
            Integer age = null;
            String role = null;
    
            List<Member> result = queryFactory
                    .selectFrom(member)
                    .where(ageAndRoleEq(age, role))
                    .fetch();
    
            System.out.println("result = " + result);
    
        }
    
        private BooleanBuilder ageAndRoleEq(Integer age, String role) {
            return ageEq(age).and(roleEq(role));
        }
    
        private BooleanBuilder ageEq(Integer age) {
            if (age == null) {
                return new BooleanBuilder();
            } else {
                return new BooleanBuilder(member.age.eq(age));
            }
        }
    
        private BooleanBuilder roleEq(String roleName) {
            if (roleName == null) {
                return new BooleanBuilder();
            }
            return new BooleanBuilder(member.roleName.eq(roleName));
        }
    
    }

     

     

     자바 8을 이용하면 코드를 줄여줄 수 있다.

    private BooleanBuilder ageEq(Integer age) {
        return nullSafeBuilder(() -> member.age.eq(age));
    }
    
    private BooleanBuilder roleEq(String roleName) {
        return nullSafeBuilder(() -> member.roleName.eq(roleName));
    }
    
    public static BooleanBuilder nullSafeBuilder(Supplier<BooleanExpression> f) {
        try {
            return new BooleanBuilder(f.get());
        } catch (IllegalArgumentException e) {
            return new BooleanBuilder();
        }
    }
    728x90
    반응형

    댓글

Designed by Tistory.