[DDD] 스프링 데이터 JPA를 이용한 조회 기능 -2

2025. 5. 8. 15:30·📚 개발자의 서재/도메인 주도 개발 시작하기
해당 포스팅은 최범균 작가님의  도메인 주도 개발 시작하기 (P.178~182)를 읽고 정리한 글입니다.

 

스프링 데이터 JPA를 이용한 스펙 구현

Spring Data JPA는 검색 조건을 표현하기 위한 인터페이스인 Specification을 제공하며 다음과 같이 정의되어 있다.

public interface Specification<T> extends Serializable {
	@Nullable
    Predicate toPredicate(Root<T> root,
                        CriteriaQuery<?> query,
                        CriteriaBuilder cb);
}

 

 

스펙 인터페이스에서 제네릭 타입 파라미터 <T>는 JPA 엔티티 타입을 의미한다. toPredicate() 메서드는 JPA Criteria API에서 조건을 표현하는 Predicate을 생성한다.

public class OrdererIdSpec implements Specification<OrderSummary> {
	
	private String ordererId;
    
    public OrdererIdSpec(String ordererId){
    	this.ordererId = ordererId;
    }
    
    @Override
    public Predicate toPredicate(Root<OrderSummary> root,
    							CriteriaQuery<?> query,
                                CriteriaBuilder cb)
    	return cb.equal(root.get(OrderSummary_.ordererId), ordererId);
    }
}

 

해당 클래스는 OrderSummary 엔티티에 대한 검색 조건을 표현한다. toPredicate() 메서드를 구현한 코드는 "ordererId" 프로퍼티 값이 생성자로 전달받은 ordererId와 동일한지 비교하는 Predicate을 생성한다.

NOTE : JPA 정적 메타 모델

정적 메타 모델은 @StaticMetamodel 애너테이션을 이용해서 관련 모델을 지정한다. 메타 모델 클래스는 모델 클래스의 이름 뒤에 '_'를 붙인 이름을 갖는다.

정적 메타 모델 클래스는 대상 모델의 각 프로퍼티와 동일한 이름을 갖는 정적 필드를 정의한다. 이 정적 필드는 프로퍼티에 대한 메타 모델로서 프로퍼티 타입에 따라 SingularAttribute, ListAttribute 등의 타입을 사용해서 메타 모델을 정의한다.

정적 메타 모델을 사용하는 대신 문자열로 프로퍼티를 지정할 수도 있지만, 오타가능성과 코드 자동 완성 기능을 사용할 수 없어 입력할 코드가 많아진다는 단점이 있다.
정적 메타 모델 클래스를 직접 작성할 수 있지만 하이버네이트와 같은 JPA 프로파이더는 정적 메타 모델을 생성하는 도구를 제공하고 있으므로 이들 도구를 사용하면 편리하다.

스펙 구현 클래스를 개별적으로 만들지 않고 별도 클래스에 스펙 생성 기능을 모아도 된다. 예를 들어 OrderSummary와 관련된 스펙 생성 기능을 한 클래스에 모을 수 있다.

public class OrderSummarySpecs {
	public static Specification<OrderSummary> ordererId(String ordererId){
    	return 
        	(Root<OrderSummary> root, CriteriaQuery<?> query,CriteriaBuilder cb) ->
            cb.equal(root.<String>get("ordererId"), ordererId);   
    }
    
    public static Specification<OrderSummary> orderDateBetween
    		(LocalDateTime from, LocalDateTime to){
    	return 
            (Root<OrderSummary> root, CriteriaQuery<?> query,CriteriaBuilder cb) ->
            cb.between(root.get(OrderSummary_.orderDate), from, to);   
	}
}

// 활용
Specification<OrderSummary> betweenSpec = OrderSummarySpecs.orderDateBetween(from, to);

 

스펙 인터페이스는 함수형 인터페이스이므로 람다식을 이용해서 객체를 생성할 수 있다. 스펙 생성이 필요한 코드는 스펙 생성 기능을 제공하는 클래스를 이용해서 조금 더 간결하게 스펙을 생성할 수 있다.


리포지터리 / DAO에서 스펙 사용하기

스펙을 충족하는 엔티티를 검색하고 싶다면 findAll() 메서드를 사용하면 된다. findAll() 메서드는 스펙 인터페이스를 파라미터로 갖는다.

public interface OrderSummaryDao extends Repository<OrderSummary, String> {
	List<OrderSummary> findAll(Specification<OrderSummary> spec);
}

 

findAll() 메서드는 OrderSummary에 대한 검색 조건을 표현하는 스펙 인터페이스를 파라미터로 갖는다. 이 메서드와 앞서 작성한 스펙 구현체를 사용하면 특정 조건을 충족하는 엔티티를 검색할 수 있다.

// 스펙 객체 생성
Specficification<OrderSummary> spec = new OrdererIdSpec("user1");
// findAll() 메서드를 이용해서 검색
List<OrderSummary> results = orderSummaryDao.findAll(spec);

보통 프로젝트에서 쿼리나 검색 조건을 만들 때는 @NamedQuery나 QueryDSL을 주로 사용해 왔다. Specification은 사용 방식이 복잡하고 러닝커브도 있어 선뜻 도입하기 어려운 느낌이 있었다. 그렇다면 굳이 Specification을 사용하는 이유가 있을까 궁금해져 이를 찾아보았다.

짧은 시간 동안 살펴본 결과, Specification을 사용하는 데 있어 뚜렷한 메리트는 크지 않다고 판단했다. 따라서 실무에서는 QueryDSL을 기본으로 활용하되, Specification은 학습 목적으로 익혀두는 것이 좋겠다고 생각했다

 

저작자표시 비영리 변경금지 (새창열림)

'📚 개발자의 서재 > 도메인 주도 개발 시작하기' 카테고리의 다른 글

[DDD] 응용 서비스와 표현 영역 -1  (0) 2025.05.10
[DDD] 스프링 데이터 JPA를 이용한 조회 기능 -3  (0) 2025.05.09
[DDD] 리포지터리와 모델 구현 -8 / 스프링 데이터 JPA를 이용한 조회 기능 - 1  (0) 2025.05.07
[DDD] 리포지터리와 모델 구현 -7  (0) 2025.05.06
[DDD] 리포지터리와 모델 구현 -6  (0) 2025.05.05
'📚 개발자의 서재/도메인 주도 개발 시작하기' 카테고리의 다른 글
  • [DDD] 응용 서비스와 표현 영역 -1
  • [DDD] 스프링 데이터 JPA를 이용한 조회 기능 -3
  • [DDD] 리포지터리와 모델 구현 -8 / 스프링 데이터 JPA를 이용한 조회 기능 - 1
  • [DDD] 리포지터리와 모델 구현 -7
l'avenirJun
l'avenirJun
  • l'avenirJun
    오늘도 꾸준히 개발
    l'avenirJun
  • 전체
    오늘
    어제
    • 분류 전체보기 N
      • 📚 개발자의 서재 N
        • 객체지향의 사실과 오해
        • Good Code, Bad Code
        • 도메인 주도 개발 시작하기 N
      • 🔧 트러블 슈팅
      • Java
      • Spring
      • 운영체제
        • 공룡책 학습
      • 알고리즘
      • GIT
      • 면접 지식
      • Spring 단기심화 2기
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    협력
    가독성
    메시지
    표현 영역
    역할
    DIP
    유스케이스
    객체지향의 사실과 오해
    애그리거트
    specification
    모듈화
    객체
    도메인 모델
    good code bad code
    애그리거트 루트
    추상화
    코딩트리조별과제
    코딩테스트
    오블완
    책임-주도 설계
    티스토리챌린지
    인터페이스
    리포지터리
    캡슐화
    책임
    코드 계약
    도메인 주도 개발 시작하기
    타입
    코드트리
    매핑 구현
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
l'avenirJun
[DDD] 스프링 데이터 JPA를 이용한 조회 기능 -2
상단으로

티스토리툴바