안녕하세요.
이번 포스팅에서는 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의 필요성이 느끼고 위와 같이 정리를 해봤습니다.
매번 느끼지만 계속해서 뭔가를 해봐야 깨닫는게 많은 것 같습니다.
'Backend' 카테고리의 다른 글
| Telegram API - PHP (0) | 2022.10.28 |
|---|---|
| 날짜/시간 클래스 정리 (java.time) (0) | 2022.10.28 |
| DTO 사용 시 참고사항 (@NoArgsConstructor, Mapper) (0) | 2022.10.27 |
| Spring boot QureyDsl 설정 (멀티 모듈) (0) | 2022.10.25 |
| 애플 로그인 및 탈퇴 과정 (2) | 2022.10.25 |