JPA Specifications 가볍게 살펴보기
스프링 Data JPA에서 복잡한 조건으로 쿼리를 수행하기 위해서 보통은 JPQL 또는 SQL(= Native Query)를 많이 사용합니다. 이 번엔 새로운 방법인 Specifications를 알아보겠습니다.
함께 살펴볼 'Spring Data JPA 공식 문서' 링크입니다.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#specifications
Spring Data JPA - Reference Documentation
Example 119. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del
docs.spring.io
우선, 기존 CrudRepository에 추가로 JpaSpecificationExecutor를 상속받아야 합니다.
public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
…
}
JpaSpecificationExecutor를 상속받게 되면 다음과 같은 형태의 메서드가 추가되어 있음을 확인할 수 있습니다.
List<T> findAll(Specification<T> spec);
Specification 정의하기
Specification 인터페이스는 다음과 같이 생겼습니다.
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
}
그리고 각각의 인자 root, builder의 사용법은 예제를 먼저 살펴보겠습니다.
public class CustomerSpecs {
public static Specification<Customer> isLongTermCustomer() {
return (root, query, builder) -> {
LocalDate date = LocalDate.now().minusYears(2);
return builder.lessThan(root.get(Customer_.createdAt), date);
};
}
public static Specification<Customer> hasSalesOfMoreThan(MonetaryAmount value) {
return (root, query, builder) -> {
// build query here
};
}
}
우선 root는 해당 객체 여기서는 'Customer' 객체를 의미합니다.
아래와 같은 코드로 현재 'Customer' 객체의 createdAt 값을 읽어올 수 있습니다.
root.get(Customer_.createdAt)
// 또는
root.get("createdAt")
builder로는 조건문을 완성할 수 있습니다.
builder.lessThan(root.get(Customer_.createdAt), date)
이 두 가지를 이용해서 18살 이하의 고객을 구하는 Specification을 정의해보면 다음과 같습니다.
Specification<User> ageLessThan18 = (root, query, cb) -> cb.lessThan(root.get("age").as(Integer.class), 18)
그리고 해당 Sepcification을 이용해서 쿼리를 실행할 수 있게 됩니다.
customerRepository.findAll(ageLessThan18)
다음엔 두 번째 인자인 CriteriaQuery<?> query에 대하여 알아보도록 하겠습니다. 👋
2022.11.24 - [10분끄적임] - '10분 끄적임' 카테고리를 만들었어요