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

API 스펙을 명확하게 규정했다고 가정합시다. 참고해서 SimpleOrderDto 를 만들겠습니다.

@RestController
@RequiredArgsConstructor
public class OrderSimpleApiController {

    private final OrderRepository orderRepository;

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

    @Data
    static class SimpleOrderDto {
        private Long orderId;
        private String name;
        private LocalDateTime orderDate;
        private OrderStatus orderStatus;
        private Address address; //...3

        public SimpleOrderDto(Order order) { //...2
            orderId = order.getId();
            name = order.getMember().getName();
            orderDate = order.getOrderDate();
            orderStatus = order.getStatus();
            address = order.getDelivery().getAddress();
        }
    }

}

  1. V2 API 의 반환값은 간단히 하기 위해서 리스트를 반환했습니다.

  2. DTO 가 entity 를 파라미터로 받는 것은 크게 문제가 되지 않습니다.

    별로 중요하지 않은 곳에서 중요한 엔티티에 의존하는 것이기 때문이죠.

    자세히

  3. Address 는 value object ( VO ) 입니다.

실행을 하면 정해진 스펙으로 최적화되어 응답이 되는 것을 확인할 수 있습니다.

Untitled

여전히 가지고 있는 문제점 - N+1 문제

그런데 V1 과 동일하게 V2 도 가지고 있는 문제점이 있습니다.

지연로딩으로 인한 데이터베이스 쿼리가 너무 많이 호출되는 문제점입니다.

지금까지 만든 API 는 order, member, delivery 란 총 3개의 테이블을 건들고 있죠.

그러면 쿼리는 처음에 order 를 조회해서 데이터를 가져오고, DTO에서 getMember() 와 getDelivery() 로 Lazy 초기화를 시키면서 member 와 delivery 의 데이터를 가져올겁니다.

영속성 컨텍스트가 찾아온 order 에서 member id 를 가지고 찾는데 없으니까 DB에서 찾아오고, 또 delivery id 가지고 찾는데 없으니까 DB에서 찾아오겠죠.

그래서 총 3개의 쿼리가 발생하면서 첫번째 주문이 완성됩니다.