[Spring Boot] JPA - JPQL 동적쿼리

김준영·2023년 12월 7일

Spring Boot

목록 보기
3/5
post-thumbnail

프로젝트의 Service 테스트중 repository의 쿼리를 줄일 수 있는 방법이 생각났다.
동적쿼리가 사용된 Repository를 개선해보자

기존 코드

매개변수로 객체의 타입과 해당 객체의 ID가 전달된다.
WordType은 PERFUME, BRAND, NOTE를 name으로 갖는 enum이다

List<Word> findByTypeAndTypeId(Long typeId, WordType wordType)

코드는 Word 테이블의 [perfume, brand, note] 열에서 타입과 맞는 열을 찾고, 해당 열과 ID값을 비교해 조회 결과를 LIST로 반환한다.
public List<Word> findByTypeAndTypeId(Long typeId, WordType wordType){
    String jpql = "SELECT w FROM Word w " +
            "LEFT JOIN w.brand b " +
            "LEFT JOIN w.note n " +
            "LEFT JOIN w.perfume p " +
            "WHERE w.wordType = :wordType " +
            "AND (b.id = :id OR n.id = :id OR p.id = :id)";

    return em.createQuery(jpql, Word.class)
            .setParameter("wordType", wordType)
            .setParameter("id", typeId)
            .getResultList();
}

Join을 사용했고, 결과를 정상적으로 반환 받을 수 있었다.
하지만 Hibernate에 의해 binding 되는 값이 4개이고, where절의 and와 or를 줄일 수 있을 것 같았다.

수정된 코드

WordType의 name을 적극 활용하기로 했다.

WordType은 PERFUME, BRAND, NOTE를 name으로 갖기에,
Word 테이블의 perfume, brand, note 열의 이름과 같다.(대문자,소문자 차이)

public List<Word> findByTypeAndTypeId(Long typeId, WordType wordType) {
        String jpql = "select w from Word w where " + "w." +
                wordType.name().toLowerCase() +
                ".id = :id";

        return em.createQuery(jpql, Word.class)
                .setParameter("id", typeId)
                .getResultList();
    }

Word 테이블에서 Type에 맞는 열만을 비교하므로, 쿼리를 줄일 수 있었다.

결론?

이 방법이 더 나은 로직인지는 확실치 않다.
다만, 확실히 쿼리가 줄었고 고민해서 코드를 고안해냈으니 다음엔 더 좋은 방법이 떠오르지 않을까.. 하는 기대를 가져보자!

0개의 댓글