> 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/v4-jpa-dto.md).

# 주문 조회 V4: JPA에서 DTO 직접 조회

JPA에서 DTO 직접 조회

OrderApiController 내부에 만든 OrderDto를 재사용하지 않고 새로 만든 이유

Repository에서 Controller의 클래스를 참조하게 될 경우 \
**Repository가 Controller를 참조하면 순환이 생겨버린다**‼️(Controller->Repository 순방향)

그래서 Repository > order > query 하위에 아래와 같이 따로 빼내서 만든다!

* **OrderItemQueryDto** //OrderItemDTO
* **OrderQueryDto** //OrderDTO\
  //orderId 없어도 되지만 일단 만듦. \
  화면에 렌더링하는 용도의 데이터라서 나중에 안 쓰려면 @JsonIgnore 처리해주면 됨.
* **OrderQueryRepository** : **EntityManager로 쿼리 작성**

**OrderQueryRepository 쿼리 작성⭐️⭐️⭐️⭐️⭐️**\
**1. findOrders()** //Order 조회\
&#x20; **: Member와 Delivery 조인해서 OrderDTO 생성해서 반환**(OrderQueryDto)\
⭐️ 이때 new 연산자로 컬렉션을 바로 받지 못한다! DB는 플랫하게 한 row씩 데이터가 들어가기 때문이다.\
&#x20;  그래서 컬렉션은 따로 처리해주어야한다.\
**2. findOrderItems(Long orderId)** // OrderItem 조회\
&#x20; **: OrderItem 과 Item 조인해서 OrderItemDTO 생성해서 반환**(OrderItemQueryDto)\
3\. **findOrderQueryDtos() //메인 메서드. 핵심 로직⭐️⭐️⭐️⭐️⭐️⭐️**\
&#x20; : OrderDTO에 List\<OrderItemDTO> 컬렉션을 넣는다!\
&#x20; 2에서 조회한 OrderItemDTO를 foreach문으로 컬렉션에 넣는다!!!&#x20;

**=>하지만 이코드에서 역시 N+1문제가 발생한다!!!!!**\
**findOrderQueryDtos > findOrders() 1번,//주문 1번**\
**foreach문에서 데이터 갯수 N개 만큼 N번//주문 상품 갯수만큼(여기서는 N = 2번)**

1. findOrders()\
   JPQL select절에서 new 연산자로 DTO 생성해서 반환 시, **select 절에 new 연산자로 바로 컬렉션을 넣을 수 없다‼️**\
   (참고)**일반 SQL 쓸 때 생각**해보면 된다. (SQL처럼 쓰는데 new로 DTO를 할 뿐.)\
   \=>**플랫하게 한줄**밖에 못 넣는다. **OrderItems**는 **일대다** 관계로 **데이터가 증가**하기 때문에 **select절에 new로 바로 못 넣는다**‼️\
   **컬렉션 List\<OrderItem>만 제외**하고 **new로 DTO 생성**(**컬렉션은 따로 넣어주는 처리!**)⭐️⭐⭐️

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

&#x20; 2\. findOrderItems(Long orderId)\
OrderItem과 Item은 다대일(ManyToOne) 관계이므로 조인해도 된다!!!

```java
private List<OrderItemQueryDto> findOrderItems(Long orderId) {
    return 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 = : orderId", OrderItemQueryDto.class)
            .setParameter("orderId",orderId)
            .getResultList();
}
```

3\. **핵심로직** : OrderItemDTO를 OrderDTO에 List\<OrderItemDTO> 컬렉션에 넣기\
findOrderItems로 조회한 List\<OrderItemDTO>를 foreach문으로 하나하나 OrderDTO의 List\<OrderItemDTO>에 넣는다!!!!!!!!!

```java
public List<OrderQueryDto> findOrderQueryDtos(){
    List<OrderQueryDto> result = findOrders();
    result.forEach(o -> {
        List<OrderItemQueryDto> orderItems = findOrderItems(o.getOrderId());//컬렉션은 제외하고 직접 채우고 있다.
        o.setOrderItems(orderItems);
    });
    return result;
}
```
