> For the complete documentation index, see [llms.txt](https://heunnajo.gitbook.io/jpa-2-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://heunnajo.gitbook.io/jpa-2-api/4.-api/v2-dto.md).

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

no properties이슈 트러블 슈팅\
원인 : getter/setter 가 없음\
해결방법 : DTO 클래스에 @Data 또는 @Getter를 추가한다. DTO라면 @Data로 해도 된다\
하지만 실무에서는 @Data가 워낙 많아서 애매한 경우는 안 쓰는 게 나을 수도 있다.

DTO(OrderDto) 생성

1. **DTO 생성**
2. **필요한 데이터 정의**
3. **생성자 생성**

![DTO 생성](https://690266786-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MevvVBGi1-NWjhdSHRP%2F-MfANTlAmjmxKj5GW1rq%2F-MfAQK15SQ_IYPJQ6tZb%2FScreen%20Shot%202021-07-22%20at%208.35.38%20AM.png?alt=media\&token=fb9be7a3-60e8-40b1-994d-55eca0a83e11)

![DTO를 반환하는 모습](https://690266786-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MevvVBGi1-NWjhdSHRP%2F-MfANTlAmjmxKj5GW1rq%2F-MfAQZfNDw8IRn-CR5Ai%2Fimage.png?alt=media\&token=c4eb47dd-d3fb-4e4b-8fb0-16b8b286b5a1)

**orderItems는 "엔티티"이기 때문에 null이 나왔다.**  V1에서처럼 stream으로 반복문 돌려서 출력할 수도 있지만 좋은 방법이 아니다.\
stream으로 돌려서 주문 상품의 상품명을 출력하는 코드 : 주문 상품 컬렉션에서 각 객체의 이름 조회

```java
List<OrderItem> orderItems = order.getOrderItems();
orderItems.stream().forEach(o -> o.getItem().getName());
```

프록시 객체 강제 초기화 : public OrderDto에서 order.getOrderItem().stream().forEach(o -> o.getItem().getName())

```java
@Data
static class OrderDto{
    private Long orderId;
    private String name;
    private LocalDateTime orderDate;
    private OrderStatus orderStatus;
    private Address address;
    private List<OrderItem> orderItems;

    public OrderDto(Order order){//생성자는 왜 있는 거지? =>생성자 주입!
        orderId = order.getId();
        name = order.getMember().getName();
        orderDate = order.getOrderDate();
        orderStatus = order.getStatus();
        address = order.getDelivery().getAddress();
        order.getOrderItems().stream().forEach(o -> o.getItem().getName());//프록시 강제 초기화
        orderItems = order.getOrderItems();
    }
}
```

![프록시 객체 강제초기화 후](https://690266786-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MevvVBGi1-NWjhdSHRP%2F-MfASFWhi-8dgReA4eCR%2F-MfASUG4CbD7IKxsmZoo%2Fimage.png?alt=media\&token=458a7005-278c-40f0-903b-5dcd3891f8f9)

우리가 만든 DTO(OrderrDto) 안에는 엔티티가 있는데, DTO 안에는 엔티티가 있으면 안 된다!\
엔티티가 외부에 노출되기 때문이다! 엔티티는 외부에 노출되면 안 되는데 이것을 DTO로 만든다고 해도 엔티티는 그대로 노출된다. **엔티티 의존성을 모두 없애야 한다!** \
**=>단순히 DTO로 만드는 것이 아니라, DTO 내부에서 엔티티가 있으면 안 된다!!!**\
(Address 같은 Value Object는 가능)

**그래서 List\<OrderItem> 도 모두 DTO로 바꿔야 한다!** 그렇지 않으면 추후에 OrderItem 엔티티 수정하게 된다면 API도 다 바뀐다!!\
\=>**statlc class OrderItemDto {...} 생성** 필요!

**OrderDto의 내부에** OrderItem도 마찬가지로 **DTO 생성, 필요한 데이터 정의, 생성자 생성**\
(참고 : 여전히 배열 타입으로 반환하고 있지만 배열 타입으로 반환❌)

![](https://690266786-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MevvVBGi1-NWjhdSHRP%2F-MfATZfzEIQ9r_LdfycH%2F-MfAY7q7ZfFe73BCYdko%2FScreen%20Shot%202021-07-22%20at%209.09.26%20AM.png?alt=media\&token=e3188ef2-6852-459e-bad5-295e7d4125aa)

코드 정리\
1\. OrderRepository에서 List\<Order> 엔티티 조회 : 실무에서는 페이징.\
2\. 반복문 돌리면서 OrderDto로 변환.\
3\. OrderDto 내에서도 List\<OrderItem> 또한 **DTO로 생성**해서 **DTO로 반환**한다!\
&#x20;  \=> OrderItemDTO 생성해서 원하는 데이터들 정의하고 리턴

```java
@GetMapping("/api/v2/orders")
public List<OrderDto> ordersV2() {
    List<Order> orders = orderRepository.findAllByCriteria(new OrderSearch());
    List<OrderDto> collect = orders.stream()
            .map(o -> new OrderDto(o))
            .collect(Collectors.toList());
    return collect;
}

```

**SQL문 분석**\
SQL은 얼마나 실행될까?

N+1문제

1. Order 엔티티(List\<Order>) 조회 : 2건 조회
2. 각 Order 객체는 반복문 돈다.\
   1\. Member 조회\
   2\. Delivery 조회\
   3\. List\<OrderItem> 조회 : 각 회원별로 주문한 상품 갯수만큼 반복. 여기서는 2개 orderItem 조회

\=>한번의 주문 조회로 5\*2 + 1 = 11개의 쿼리가 발생하는 것을 알 수 있다.

N+1문제\
Order 조회 시, 2건의 Order 존재.

첫번째 Order부터 반복문 돈다. - Member, Address, List\<OrderItem> 가져온다.\
&#x20; List\<OrderItem> 모두 지연 로딩.

\=>컬렉션으로 일대다 관계에서 테이블을 조회하면 N+1 문제 발생!
