# 주문 조회 V5: JPA에서 DTO 직접 조회 - 컬렉션 조회 최적화

**이전 버전과 차이점(핵심)**

Before : foreach 돌 때마다 쿼리문 실행\
After : **in 절로** 메모리에 데이터 한번에 가져온 후, foreach 돌 때마다 **메모리에서** 값 매칭되는 데이터 셋팅\
\=>쿼리 2번으로 최적화 가능!

1. OrderApiController
2. OrderQueryRepository\
   **findAllByDto\_optimization(메인)**\
   findOrderItemMap//리팩토링 결과 생성된 메서드

   toOrderIds//리팩토링 결과 생성된 메서드

OrderApiController

```java
@GetMapping("/api/v5/orders")
public List<OrderQueryDto> ordersV5(){
    return orderQueryRepository.findAllByDto_optimization();
}
```

OrderQueryRepository

1. **findAllByDto\_optimization(메인)**\
   **일단 findOrders()로 Member & Delivery 조인해서 한번에 Order 조회하는 것은 동일하다.**

```java
public List<OrderQueryDto> findAllByDto_optimization() {
        List<OrderQueryDto> result = findOrders();
        Map<Long, List<OrderItemQueryDto>> orderItemMap = findOrderItemMap(toOrderIds(result));
        result.forEach(o -> o.setOrderItems(orderItemMap.get(o.getOrderId())));
        return result;
}
```

&#x20; 2\. findOrderItemMap(List\<Long> orderIds)\
&#x20;   OrderItem 조회쿼리 앞과 비슷하지만 여기서 핵심은 **in절**로 orderId 하나씩 조회하는 게 아니라 한번에 다 가져온다?! 그래서 orderId**s 를 orderItems에 저장한다.**

orderItems의 id, orderItemDTO를 Map으로 저장=> **key로 조회 시 O(1)으로 성능 최적화&코드 간결❤️**

```java
private Map<Long, List<OrderItemQueryDto>> findOrderItemMap(List<Long> orderIds) {
    List<OrderItemQueryDto> orderItems = em.createQuery("select new jpabook_v2.jpashop_v2.repository.order.query.OrderItemQueryDto(oi.order.id, i.name, oi.orderPrice, oi.count)" +
            " from OrderItem oi" +
            " join oi.item i" +
            " where oi.order.id in :orderIds", OrderItemQueryDto.class)
            .setParameter("orderIds", orderIds)//findOrders()로 가져온 List<OrderQueryDto>를 stream, map으로 돌려서 id를 다 뽑는다!
            .getResultList();

    Map<Long, List<OrderItemQueryDto>> orderItemMap = orderItems.stream()
            .collect(Collectors.groupingBy(orderItemQueryDto -> orderItemQueryDto.getOrderId()));
    return orderItemMap;
}
```

&#x20; 3\. toOrderIds(List\<OrderQueryDto> result)\
&#x20; **findOrders()로 조회한 List\<OrderQueryDto>를 foreach로 각각의 Id들을 리스트로 만들어서 반환**

```java
private List<Long> toOrderIds(List<OrderQueryDto> result) {
    List<Long> orderIds = result.stream()
            .map(o -> o.getOrderId())
            .collect(Collectors.toList());
    return orderIds;
}
```

**fetch join과 트레이드 오프**

&#x20;\- : JPA에서 DTO 직접 조회 시, 상당히 많은 쿼리들을 직접 작성\
\+ : select쿼리문이 fetch join에 비해 상당히 적다!!

결론, 정리

* 쿼리 : root 1번, 컬렉션 1번(총 2번)
* ToOne 관계들 먼저 join으로 조회하고, **여기서 얻은 식별자 orderId로 ToMany관계인 orderItem을 한번에 조회**
* MAP을 사용해서 매칭 성능 향상(O(1))


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://heunnajo.gitbook.io/jpa-2-api/4.-api/v4-jpa-dto-1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
