givepro

JPA Specification 활용하여 다중 조건 쿼리문 구현 본문

백엔드/SpringBoot

JPA Specification 활용하여 다중 조건 쿼리문 구현

givepro 2022. 10. 28. 11:25
반응형

안녕하세요.

이번 포스팅에서는 JPA Specification에 대해서 다루고자 합니다.

 

Spring JPA Specification

Spring JPA에서 제공하는 검색 조건을 메서드 형태로 추상화하여 Repository 인터페이스에서

해당 검색 조건을 조합하고 쿼리하기 쉽게 할 수 있는 기능입니다.

WHY?

여러 조건에 대해서 JpaRepository로 구현했을때 복잡해지고 보기 힘들어지는 코드

List<Sample> findAllByHelloIdAndViewerTypeCodeAndDeletedFalseAndValidTrueOrderBySeqAsc(Long helloId, String viewerTypeCode);

위 코드를 보기만해도 머리가 아파지는 느낌이다. (도대체 무슨 조건이 저렇게 많나 싶은)

 

물론 간단한 조건의 경우는 위의 방식과 같이 처리하지만,

재사용성이 높은, 중복된 코드 등 효율적으로 관리하기 위해서는 다른 방법을 쓰는것이 필요했다.

 

HOW

public interface SampleRepository extends JpaRepository<Sample, Long>, JpaSpecificationExecutor<Sample> {

}

Repository 인터페이스에 JpaSpecificationExecutor 상속해준다.

import javax.persistence.criteria.Predicate;

public class SampleSpecification {

    public static Specification<Sample> of (Long helloId, String viewerTypeCode, boolean valid) {
        return (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            predicates.add(criteriaBuilder.equal(root.get("hello"), helloId));
            predicates.add(criteriaBuilder.equal(root.get("viewerType").get("code"), viewerTypeCode));
            if (valid) predicates.add(criteriaBuilder.equal(root.get("valid"), Boolean.TRUE));

            predicates.add(criteriaBuilder.equal(root.get("deleted"), Boolean.FALSE));

            query.orderBy(criteriaBuilder.asc(root.get("seq")));

            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
    }

}

별도의 Specification 클래스를 만들어주도록 합니다.

 

관련된 내용을 찾아보면 소스는 많으나 저 코드에 대한 자세한 설명이 부족해서 나름 찾아가봐면서 정리를 해봤습니다.

1. root

영속적 엔티티를 나타내는 쿼리 표현식과 같다. 즉 Sample Entity라고 생각하면 된다.

root.get("hello") → Sample의 hello 필드를 말하는 것

 

2. query

이름 그대로 작성되는 쿼리로 생각하면 된다. 위에서는 order by 구문을 설정

 

3. criteriaBuilder

일단 criteria가 뭔지부터 알아야 한다.

Criteria 는 JPQL 의 작성을 도와주는 빌더 클래스이다
javax.persistence.criteria 패키지에 존재
Criteria 쿼리는 빌더(CriteriaBuilder) 필요, EntityManager나 EntityManagerFactory로 생성
Criteria 쿼리 빌더에서 Criteria 쿼리(CriteriaQuery)를 생성

단순하게 말하면 위 Specification에서 쿼리를 생성해주는 빌더라고 생각하면 될 것 같다.

 

4. Predicate

직역하면 "서술어"라고 합니다. 여기서는 쿼리문의 Where절에 들어가는 조건문이라고 생각하시면 됩니다.

위 코드에서는 조건문을 List로 담고 criteriaBuilder에 담은 조건문을 전달해주는 역할인 것 같습니다.

 


이전에는 남들이 작성된 코드를 가져와서 사용하다보니 왜 사용하는지에 대해 의문이 있었으나,

최근 프로젝트를 진행하면서 중복된 쿼리문, 재사용성을 위해서 Specification의 필요성이 느끼고 위와 같이 정리를 해봤습니다.

 

매번 느끼지만 계속해서 뭔가를 해봐야 깨닫는게 많은 것 같습니다.

Comments