실전! 스프링 부트와 JPA 활용1(웹 애플리케이션 개발)

Ch06. 상품 도메인 개발 - 주문 검색 기능 개발

webmaster 2021. 12. 6. 23:08
728x90

JPA에서 동적 쿼리를 어떻게 해결해야 하는가?

String jpql = "select o from Order o join o.member m" +
                "where o.status = :status" +
                " and m.name like :name";
em.createQuery(jpql,Order.class)//JPA에서 Join
                .setParameter("status",orderSearch.getOrderStatus())
                .setParameter("name",orderSearch.getMemberName())
                //.setFirstResult(100)//페이징이 가능
                .setMaxResults(1000) // 최대 1000건
                .getResultList();

해당 로직을 동적 쿼리로 작성하기 위해서는 어떻게 해야 되나? 

방법 1 : 문자열을 따로 빌드하여 작성한다.

String jpql = "select o From Order o join o.member m";
boolean isFirstCondition = true;
//주문 상태 검색
if (orderSearch.getOrderStatus() != null) {
	if (isFirstCondition) {
		jpql += " where";
		isFirstCondition = false;
	} else {
		jpql += " and";
	}
	jpql += " o.status = :status";
}
//회원 이름 검색
if (StringUtils.hasText(orderSearch.getMemberName())) {
  	if (isFirstCondition) {
  		jpql += " where";
  		isFirstCondition = false;
  	} else {
  		jpql += " and";
	}
	jpql += " m.name like :name";
}
TypedQuery<Order> query = em.createQuery(jpql, Order.class)
.setMaxResults(1000);
if (orderSearch.getOrderStatus() != null) {
	query = query.setParameter("status", orderSearch.getOrderStatus());
}
if (StringUtils.hasText(orderSearch.getMemberName())) {
	query = query.setParameter("name", orderSearch.getMemberName());
}
return query.getResultList();
  • 복잡하고 오류가 발생할 가능성이 너무 높다.
  • 실무에서 사용하지 못한다.

방법 2 : Criteria 사용(JPA에서 표준으로 동적쿼리 문제를 해결하기 위해 제공하는 기술)

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> cq= cb.createQuery(Order.class);
Root<Order> o = cq.from(Order.class);
Join<Object,Object> m = o.join("member", JoinType.INNER);

List<Predicate> criteria = new ArrayList<>();
//주문 상태 검색
if(orderSearch.getOrderStatus() != null){
	Predicate status = cb.equal(o.get("status"), orderSearch.getOrderStatus());
    criteria.add(status);
 }
 //회원 이름 검색
 if(StringUtils.hasText(orderSearch.getMemberName())){
 	Predicate name = cb.like(m.<String>get("name"),"%" + orderSearch.getMemberName() + "%");
    criteria.add(name);
}
cq.where(criteria.toArray(new Predicate[criteria.size()]));
TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000);
return query.getResultList();
  • 실무에서는 사용하지 못한다( 유지보수성이 좋지 않다)
  • 어떤 쿼리를 동작시키고, 어떤 쿼리를 조인하는 것인지 파악하기 힘들다.

방법 3 : QueryDsl을 이용한다

QOrder order = QOrder.order;
QMember member = QMember.member;
return query
		.select(order)
        .from(order)
        .join(order.member, member)
        .where(statusEq(orderSearch.getOrderStatus()),
        		nameLike(orderSearch.getMemberName()))
        .limit(1000)
        .fetch();
  • 가장 현실적인 방법 ( 실무에서 가장 많이 사용)
  • 초기 설정하는 비용이 있긴 해도, 개발 생산성이 크게 증가
728x90