# 주문 조회 V6: JPA에서 DTO 직접 조회, 플랫 데이터 최적화

Order와 OrderItem, Item을 join해서 한번에 다 가져오도록 해본다!\
SQL에서는 flat하게 한줄로 나오기 때문에 이에 맞춰야한다.

OrderQueryDto로 바꾸고 싶다면 직접 중복을 제거해야한다.(a.k.a 노가다)

```java
@GetMapping("/api/v6/orders")
public List<OrderFlatDto> ordersV6(){
    return orderQueryRepository.findAllByDto_flat();
}
```

작전 : 한번에 다 join해서 쿼리가 한번만 실행되게 한다.\
\=>당연히 중복 결과가 나온다!\
API Specification은 이전과 동일하게 해서 중복되는 데이터들은 직접 복잡한 쿼리들을 작성해서 제거한다.

그러면 한번의 쿼리로 원하는 데이터를 조회할 수 있다!

```java
@GetMapping("/api/v6/orders")
  public List<OrderQueryDto> ordersV6() {
      List<OrderFlatDto> flats = orderQueryRepository.findAllByDto_flat();
      return flats.stream()
              .collect(groupingBy(o -> new OrderQueryDto(o.getOrderId(),
  o.getName(), o.getOrderDate(), o.getOrderStatus(), o.getAddress()),
                      mapping(o -> new OrderItemQueryDto(o.getOrderId(),
  o.getItemName(), o.getOrderPrice(), o.getCount()), toList())
              )).entrySet().stream()
              .map(e -> new OrderQueryDto(e.getKey().getOrderId(),
  e.getKey().getName(), e.getKey().getOrderDate(), e.getKey().getOrderStatus(),
  e.getKey().getAddress(), e.getValue()))
              .collect(toList());
}
```

**OrderFlatDto**\
OrderDTO와 OrderItemDTO를 합친다!

```java
package jpabook_v2.jpashop_v2.repository.order.query;

import jpabook_v2.jpashop_v2.domain.Address;
import jpabook_v2.jpashop_v2.domain.OrderStatus;
import lombok.Data;

import java.time.LocalDateTime;

@Data
public class OrderFlatDto {
    private Long orderId;
    private String name;
    private LocalDateTime orderDate;
    private OrderStatus orderStatus;
    private Address address;

    private String itemName;
    private int orderPrice;
    private int count;

    public OrderFlatDto(Long orderId, String name, LocalDateTime orderDate, OrderStatus orderStatus, Address address, String itemName, int orderPrice, int count) {
        this.orderId = orderId;
        this.name = name;
        this.orderDate = orderDate;
        this.orderStatus = orderStatus;
        this.address = address;
        this.itemName = itemName;
        this.orderPrice = orderPrice;
        this.count = count;
    }
}
```

**OrderQueryRepository : 쿼리 작성**

```java
public List<OrderFlatDto> findAllByDto_flat() {
    return  em.createQuery(
            "select new jpabook_v2.jpashop_v2.repository.order.query.OrderFlatDto(o.id, m.name, o.orderDate, o.status, d.address, i.name, oi.orderPrice, oi.count)" +
                    " from Order o" +
                    " join o.member m" +
                    " join o.delivery d" +
                    " join o.orderItems oi" +
                    " join oi.item i", OrderFlatDto.class)
            .getResultList();
}
```

장점 : **쿼리 한번**

단점

* 쿼리는 한번이지만 조인으로 인해 DB에서 애플리케이션에 전달하는 데이터에 중복 데이터가 추가되므로 상황에 따라 V5 보다 더 느릴 수 도 있음!
* 애플리케이션에서 추가 작업이 크다.
* **페이징 불가능**\
  OrderFlatDto 나 OrderItems 관련 : 페이징 가능할 수도 있지만 Order에 대해서는 페이징 불가능.\
  \=>DB에서는 여전히 중복된 데이터가 포함된 테이블이 있기 때문.\
  ex) DB : 4, 4, 11, 11 주문번호에 따라 이렇게 저장되있는데\
  우리가 원하는 것은 4,11 이다. 그래서 페이징으로 (0,2) 을 하면 4,4가 나와버린다.


---

# 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-2.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.
