본문 바로가기

Web/DB

[Spring framework Data JPA] 5.1.5. Specifications

728x90

https://docs.spring.io/spring-data/jpa/docs/2.7.7/reference/html/#specifications

 

Spring Data JPA - Reference Documentation

Example 109. 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

 

틀린 해석이나 내용을 찾으시면 알려주세요 감사합니다 🤓

 


5.1.5. Specifications

 

JPA 2에서는 프로그래밍 방식으로 쿼리를 작성할 수 있는 API가 도입되었다

조건을 작성하여 domain class에 대한 query의 where절을 정의한다

 

Spring Data JPA는 EricEvans의 저서 "Domain Driven Desigh" 의 개념을 가져왔고

JPA 기준 API로 제공한다.

JpaSpecificationExecutor 인터페이스로 저장소 인터페이스를 확장할 수 있다.

 

 

사용법

public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
 …
}

 

The additional interface has methods that let you run specifications in a variety of ways. 

List<T> findAll(Specification<T> spec);

 

Specification은 다음과 같은 interface로 정의된다

public interface Specification<T> {
  Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
            CriteriaBuilder 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
    };
  }
}

Customer_ 유형은 JPA 메타모델 생성기를 사용하여 생성된 메타모델 유형이다

따라서 Customer_.createdAt 식은 고객이 Date 유형의 createdAt 속성을 가지고 있다고 가정하고 진행한다

그 외에도 비즈니스 요구 사항 추상화 수준에 대한 몇 가지 기준을 표현하고 실행 가능한 사양을 만든다

클라이언트는 다음과 같이 사용할 수 있다.

 

Using a simple Specification

List<Customer> customers = customerRepository.findAll(isLongTermCustomer());

 

간단한 쿼리에서 Specification을 작성하지 않는 이유는 간단하다

Single Specification의 사용은 일반 쿼리 선언과 비교 하여 진가를 발휘하지못한다

Specification은 여러 Specifications 들을 만들 때 빛을 발한다

 

Combined Specifications

MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List<Customer> customers = customerRepository.findAll(
  isLongTermCustomer().or(hasSalesOfMoreThan(amount)));

 

Specification instnace를 연결하고 결합하는 glue-code 방법을 제공한다

기존 구현과 결합하면 데이터 액세스 계층을 확장할 수 있다

728x90

'Web > DB' 카테고리의 다른 글

[SQL] 정규화(Normalization)  (0) 2023.03.05
[Hibernate orm] 11. Fetching  (0) 2023.02.16
[Hibernate validator] 5. Grouping constraints  (0) 2023.02.06
[Hibernate validator] 6. Creating custom constraints  (1) 2023.02.02
[Hibernate orm] 2.7. Associations  (1) 2023.02.02