# 간단한 주문 조회 V2: 엔티티를 DTO로 변환

API Specification을 명확하게 규정해야한다!

**주문 조회 시 사용하는 DTO : SimpleOrderDto**

```java
@Data
static class SimpleOrderDto {
    private Long orderId;
    private String name;
    private LocalDateTime orderDate; //주문시간 private OrderStatus orderStatus;
    private OrderStatus orderStatus;
    private Address address;
    public SimpleOrderDto(Order order) {
        orderId = order.getId();
        name = order.getMember().getName();
        orderDate = order.getOrderDate();
        orderStatus = order.getStatus();
        address = order.getDelivery().getAddress();
    }
}
```

```java
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2(){
    List<Order> orders = orderRepository.findAllByCriteria(new OrderSearch());
    //Order를 DTO로 변환!
    List<SimpleOrderDto> result = orders.stream()
            .map(o -> new SimpleOrderDto(o))
            .collect(Collectors.toList());
    return result;
}
```

람다식을 이용해서 리팩토링하면 다음처럼 코드 개선 가능\
o->new SimpleOrderDto(o) : 생성자로 바로 넘기기 때문에

```java
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2(){
    return orderRepository.findAllByString(new OrderSearch)).stream()
            .map(SimpleOrderDto::new)
            .collect(toList());
}
```

V1, V2 문제점

**지연 로딩**으로 인해 DB 쿼리가 너무 많이 호출된다!\
V2 : Order, Member, Delivery 총 3개의 테이블 조회한다!

주문 조회 시 총 5번의 쿼리가 나간다! =>**N+1 문제 발생**‼️

1. Order 조회 : 주문 결과 2건
2. (루프1) DTO의 getMember().getName()로 MEMBER 조회
3. &#x20;            DTO의 getDelivery().getAddress()로 DELIVERY 조회
4. (루프2) DTO의 getMember().getName()로 MEMBER 조회
5. &#x20;            DTO의 getDelivery().getAddress()로 DELIVERY 조회

첫번째 쿼리(Order 조회) 나가면 이로 인해 N번만큼 쿼리 추가 실행\
Order 조회(1) + N(2) = 1 + 회원 N + 배송 N\
\&#xNAN;**=>Order가 총 2개 : 1+ 2 + 2 = 5(최악의 경우)**

지연로딩은 영속성 컨텍스트에서 조회하므로, 이미 조회된 경우 쿼리를 생략한다.\
실제로 회원 아이디를 동일하게 하고 주문하면\
1 + 1+ 1 + 0 + 1 = 4 =>총 4번의 쿼리가 나가는 것을 확인할 수 있다.
