✔ 스프링 데이터 JPA와 QueryDSL 통합

스프링 데이터 JPA는 2가지 방법으로 QueryDSL을 지원한다. - org.springframework.data.querydsl.QueryDslPredicateExecutor - org.springframework.data.querydsl.QueryDslRepositorySupport

1. QueryDslPredicateExecutor 사용

첫 번째 방법은 리포지토리에서 QueryDslPredicateExecutor를 상속받으면 된다.

public interface ItemRepository extends JpaRepository<Item, Long>, QueryDslPredicateExecutor<Item>{}

이제 상품 리포지토리에서 QueryDSL을 사용할 수 있다.

//QueryDSL 사용 예제/*QueryDSL이 생성한 쿼리 타입으로 장난감이라는 이름을 포함하고 있으면서 10000~20000원인 상품을 검색*/QItem item = QItem.item;Iterable<Item> result = itemRepository.findAll(        item.name.contains("장난감").and(item.price.between(10000,20000))    )

QueryDSL을 검색조건으로 사용하면서 스프링 데이터 JPA가 제공하는 페이징과 정렬 기능도 함께 사용할 수 있다.

public interface QueryDslPredicateExecutor<T>{    T findOne(Predicate predicate);    Iterable<T> findAll(Predicate predicate);    Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);    Page<T> findAll(Predicate predicate, Pageable pageable);    long count(Predicate predicate);}

QueryDslPredicateExecutor는 편리하게 QueryDSL을 사용할 수 있지만 기능에 한계가 있다.

예를 들어 join, fetch를 사용할 수 없다.(JPQL의 묵시적 조인은 가능) 따라서 QueryDSL이 제공하는 다양한 기능을 사용하려면 JPAQuery를 직접 사용하거나 스프링 데이터 JPA가 제공하는 QueryDslRepositorySupport를 사용해야 한다.

2. QueryDslRepositorySupport 사용

스프링 데이터 JPA가 제공하는 QueryDslRepositorySupport를 상속받아 사용하면 조금 더 편리하게 QueryDSL을 사용할 수 있다.

public interface CustomOrderRepository{    public List<Order> search(OrderSearch orderSearch);}

스프링 데이터 JPA가 제공하는 공통 인터페이스는 직접 구현할 수 없기 때문에 CustomOrderRepository라는 사용자 정의 리포지토리를 만들었다.

//QuerydslRepositorySupport를 사용하는 코드public class OrderRepositoryImpl extends QuerydslRepositorySupport implements CustomOrderRepository{    public OrderRepositoryImpl()    {        super(Order.class);    }    @Override    public List<Order> search(OrderSearch orderSearch)    {        QOrder order = QOrder.order;        QMember member = QMember.member;        JPQLQuery query = from(order);        if (StringUtils.hasText(orderSearch.getMemberName()))        {            query.leftJoin(order.member, member)                    .where(member.name.contains(orderSearch.getMemberName()));        }        if (orderSearch.getOrderStatus() != null)        {            query.where(order.status.eq(orderSearch.getOrderStatus()));        }        return query.fetch();    }}

웹 애플리케이션 만들기에서 사용했던 주문 내역 검색 기능을 QuerydslRepositorySupport를 사용해 QueryDSL로 구현했다.

검색 조건에 따라 동적으로 쿼리를 생성한다.

생성자에서 QuerydslRepositorySupport에 엔티티 클래스 정보를 넘겨주어야 한다.

//QuerydslRepositorySupport의 핵심 기능@Repositorypublic abstract class QuerydslRepositorySupport{    //엔티티 매니저 반환    protected EntityManager getEntityManager() {        return entityManager;    }    //from 절 반환    protected JPQLQuery<Object> from(EntityPath<?>... paths) {        return querydsl.createQuery(paths);    }    //QueryDSL delete 절 반환    protected DeleteClause<JPADeleteClause> delete(EntityPath<?> path) {        return new JPADeleteClause(entityManager, path);    }    //QueryDSL update 절 반환    protected UpdateClause<JPAUpdateClause> update(EntityPath<?> path) {        return new JPAUpdateClause(entityManager, path);    }    //Querydsl을 편하게 사용하도록 돕는 헬퍼 객체 반환    protected Querydsl getQuerydsl() {        return this.querydsl;    }