[스프링 활용2] 주문 조회 V2: 엔티티를 DTO로 변환

atdawn·2024년 8월 18일

SPRING BOOT+JPA

목록 보기
43/49

참고 : [실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화] - 김영한


OrderApiController

/*
* V2. 엔티티를 조회해서 DTO로 변환(fetch join 사용X)
* - 트랜잭션 안에서 지연 로딩 필요
*/

  @GetMapping("/api/v2/orders")
    public List<OrderDto> ordersV2() {
        List<Order> orders = orderRepository.findAllByString(new OrderSearch());
        List<OrderDto> result = orders.stream()
                .map(o -> new OrderDto(o))
                .collect(toList());
        return result;
    }
    
 @Data
    static class OrderDto {
        private Long orderId;
        private String name;
        private LocalDateTime orderDate; //주문시간
        private OrderStatus orderStatus;
        private Address address;
        private List<OrderItemDto> orderItems;
        public OrderDto(Order order) {
            orderId = order.getId();
            name = order.getMember().getName();
            orderDate = order.getOrderDate();
            orderStatus = order.getStatus();
            address = order.getDelivery().getAddress();
            orderItems = order.getOrderItems().stream()
                    .map(orderItem -> new OrderItemDto(orderItem))
                    .collect(toList());
        }
    }
    
 @Data
    static class OrderItemDto {
        private String itemName;//상품 명
        private int orderPrice; //주문 가격
        private int count; //주문 수량

        public OrderItemDto(OrderItem orderItem) {
            itemName = orderItem.getItem().getName();
            orderPrice = orderItem.getOrderPrice();
            count = orderItem.getCount();
        } }
  • 간단한 주문조회와 달라진 점은 OrderDto 생성자에서 OrderItems를 초기화하는 방법이다.
...
private List<OrderItem> orderItems;
 public OrderDto(Order order) {
 ...
 orderItems=order.getOrderItems;
 ...
  • 위의 코드는 orderItems 엔티티를 직접 노출하게 되기때문에 적절하지 않다.
  • 위의 결과처럼 OrderItem을 DTO로 변환하지 않고 엔티티를 그대로 JSON으로 직렬화할 때, 결과가 null이 나온다.
    • OrderItem 엔티티는 Order 엔티티와 지연 로딩(Lazy Loading) 관계로 설정되어 있어, OrderItem 객체는 처음에는 실제 데이터가 아닌 프록시 객체로 존재하고, 해당 데이터가 실제로 필요할 때 데이터베이스에서 조회된다.
    • 만약 트랜잭션 범위를 벗어난 상태에서 OrderItem을 조회하려고 하면, 프록시 객체가 초기화되지 못해 실제 데이터가 없게 된다. 이 경우, Jackson 라이브러리 같은 JSON 직렬화 도구가 프록시 객체를 직렬화하지 못해 null로 처리한다.
  • 그렇기 때문에 orderItems 또한 OrderItemDto로 변환하여 조회한다.
    • OrderItemDto에서는 OrderItem의 노출하고 싶은 정보만 설정하면 더욱 효율적이다.

OrderItemDTO를 활용하면 위와 같이 올바른 결과가 나온다!

하지만 여전히 N+1 문제는 발생한다.

profile
복습 복습 복습

0개의 댓글