# 간단한 주문 조회 V4: JPA에서 DTO로 바로 조회(버전별 비교 분석)

V2, V3까지는 엔티티를 조회해서 DTO로 변환했다.

이제는 JPA에서 DTO로 바로 조회한다!

* 일반적인 SQL을 사용할 때 처럼 원하는 값을 선택해서 조회
* new 명령어를 사용해서 JPQL의 결과를 DTO로 즉시 변환
* SELECT 절에서 원하는 데이터를 직접 선택하므로 DB 애플리케이션 네트웍 용량 최적화(생각보다 미비)
* 리포지토리 재사용성 떨어짐, API 스펙에 맞춘 코드가 리포지토리에 들어가는 단점

**Repository에서 Controller 의존관계 생기면 안된다!**\
**컨트롤러에서 서비스, 서비스에서 리포지토리 이렇게 가급적이면 한 방향으로 흘러야한다!**

JPA는 **엔티티**나 임베디드 타입 같은 **값 타입만 반환 가능**하다.\
(DTO에서 생성자가 매핑해주는 것이 아니다.)\
**DTO 반환하려면 new 연산자를 꼭 써야한다!**\
new 연산자로 엔티티를 바로 넘기면 안 된다!왜냐하면 엔티티가 식별자로 넘어가기 때문이다!(??)

기존의 SimpleDto를 클래스로 따로 뺀다. - OrderSimpleQueryDto\
\=>리포지토리 하위에 패키지를 두고 여기에 별도로 둔다!

```java
@Data
public class OrderSimpleQueryDto {
        private Long orderId;
        private String name;
        private LocalDateTime orderDate; //주문시간 private OrderStatus orderStatus;
        private OrderStatus orderStatus;
        private Address address;
        public OrderSimpleQueryDto(Order order) {
            orderId = order.getId();
            name = order.getMember().getName();//LAZY 초기화! 영속성 컨텍스트 조회해서 없으면 DB MEMBER 조회 쿼리 날린다!
            orderDate = order.getOrderDate();
            orderStatus = order.getStatus();
            address = order.getDelivery().getAddress();//LAZY 초기화! 영속성 컨텍스트 조회해서 없으면 DB DELIVERY 조회 쿼리 날린다!
        }
}
```

내부의 생성자를 통해 엔티티를 받고 있지만, 엔티티를 받으면 안 된다!

**V3, V4 차이점**

|                               | V3                                          | V4                                                                            |
| ----------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------- |
| 차이점                           | fetch join으로 모든 데이터를 select문으로 구성           | 원하는 데이터만 select 쿼리 직접 작성                                                      |
| <p>Order</p><p>Repository</p> | List<**Order**> findAllWithMemberDelivery() | List<**OrderSimpleQueryDto**> findOrderDto()                                  |
|                               | 외부는 건드리지 않고 내부에서 fetch join으로 성능 튜닝=>재사용 가능 | JPQL로 원하는 데이터들 쿼리를 직접 작성했으므로 재사용❌                                             |
| <p>반환 타입,</p><p>조회 타입</p>     | **엔티티 반환&조회**                               | <p><strong>DTO 반환&조회</strong>=><strong>수정/변경❌</strong></p><p>엔티티가 아니기 때문에</p> |
|                               | 코드 작성 쉬움                                    | 쿼리문 직접 작성=>코드 복잡해지기 쉬움                                                        |

* 리포지토리 용도 : 엔티티, 객체 그래프 조회 등에 사용\
  하지만 V4에서는 리포지토리가 API 스펙에 맞춰 작성되었다!
* 리포지토리 재사용성 떨어짐, API 스펙에 맞춘 코드가 리포지토리에 들어가는 단점\
  \=>리포지토리에서 API에 의존하고 있다고 할 수 있다.
* 대부분의 경우 V3, V2 성능 차이 미비\
  \=> 요즘 네트워크 밴더들이 제공하는 네트워크 상태나 질이 좋기 때문에 빠르다.
* V3, V4의 쿼리 차이는 select문에서 무엇을 얼마나 조회하느냐인데\
  **실제 성능에 영향을 끼치는 것은 조인이나 where절**이다. \
  애플리케이션 전체 관점에서 보면 select절은 성능에 크게 영향을 주지는 않는다. 문제는 따로 있다!

만약 select해야하는 것이 20-30개, 현재의 API가 트래픽이 엄청 많이 들어오는가?를 고민하면서 최적화.

**⭐️V4 개선** : **화면에 의존적인 부분을 리포지토리와 분리**\
**Repository 하위에 성능최적화한 쿼리용 패키지를 하나 만든다!**\
**리포지토리**는 **엔티티를 검색/조회**하고, **필요에 따라 fetch join**으로 최적화하는것 정도만 한다!!

* OrderSimpleQueryRepository리포지토리 : 조회 전용 리포지 토리(JPQL 쿼리 최적화)
* OrderSimpleQueryDto 리포지토리 : DTO 직접 조회

⭐️**쿼리 방식 선택 권장 순서 (웬만하면 2번에서 다 해결된다고 함.)**

1. 우선 엔티티를 DTO로 변환하는 방법을 선택한다. - V2
2. 필요하면 페치 조인으로 성능을 최적화 한다. 대부분의 성능 이슈가 해결된다. - V3
3. 그래도 안되면 DTO로 직접 조회하는 방법을 사용한다. - V4
4. 최후의 방법은 JPA가 제공하는 네이티브 SQL이나 스프링 JDBC Template을 사용해서 SQL을 직접
