JPA 활용편 - 동적쿼리

Stella·2022년 5월 10일
0

Java

목록 보기
11/18

정적 쿼리

  • 어떤 조건 또는 상황에도 변경되지 않음.

parameter가 반드시 넘어오는 경우

   public List<Order> findAll(OrderSearch orderSearch){
       return  em.createQuery("select o from Order o join o.member m"+" where o.status = :status "+" and m.name like :name", Order.class)
               .setParameter("status",orderSearch.getOrderStatus())
               .setParameter("name", orderSearch.getMemberName())
               .setFirstResult(100) //100부터 시작해서
               .setMaxResults(1000) //최대 1000건
               .getResultList();

    }

parameter가 없는 경우

 public List<Order> findAll(OrderSearch orderSearch){
       return  em.createQuery("select o from Order o join o.member m", Order.class)
               .setFirstResult(100) //100부터 시작해서
               .setMaxResults(1000) //최대 1000건
               .getResultList();

    }

동적쿼리

  • 특정 조건들이나 상황에 따라 변경됨.
    ex) 검색 기능
    - parameter 값이 없으면 전체 데이터 검색,
    - parameter 값이 있으면 그 값으로 데이터 검색.

1. JPQL 사용

    public List<Order> findAll(OrderSearch orderSearch){
        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();

    }

단점

  • jpql을 문자열로 만든 후, string을 추가하는 방식 --> jpql에 띄어쓰기 하나라도 틀리면 오류발생.

2. JPA Criteria

    public List<Order> findAllByCriteria(OrderSearch orderSearch){
        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(cb.and(criteria.toArray(new Predicate[criteria.size()])));
        TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000);
        return query.getResultList();
    }

단점

  • 유지보수 제로에 가까움. 무슨 쿼리가 생성될 지 예측 하기어려움.
  • Criteria는 Spring의 표준 스펙, but 실무에서 사용하지 않음.

3. Querydsl

public List<Order> findAll(OrderSearch orderSearch){

	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();
   }
   
   private BooleanExperssion statusEq(OrderStatus statusCond){
   		if(statusCond == null){
        	return null;
       }
       return order.status.eq(statusCond);
 }
 
 private BooleanExperssion nameLike(String nameCond) {
 		if(!StringUtils.hasText(nameCond)){
        	return null;
       }
       return member.name.like(nameCond);
profile
Hello!

0개의 댓글