๐ŸŒฑย API ๊ฐœ๋ฐœ ๊ณ ๊ธ‰ - ์ปฌ๋ ‰์…˜ ์กฐํšŒ ์ตœ์ ํ™”

์ฃผ๋ฌธ ์กฐํšŒ V1: ์—”ํ‹ฐํ‹ฐ ์ง์ ‘ ๋…ธ์ถœ

/api/OrderApiController.java

import jpabook.jpashop.domain.Address;
import jpabook.jpashop.domain.Order;
import jpabook.jpashop.domain.OrderItem;
import jpabook.jpashop.domain.OrderStatus;
import jpabook.jpashop.repository.OrderRepository;
import jpabook.jpashop.repository.OrderSearch;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequiredArgsConstructor
public class OrderApiController {

    private final OrderRepository orderRepository;

    /**
     * V1. ์—”ํ‹ฐํ‹ฐ ์ง์ ‘ ๋…ธ์ถœ
     * - Hibernate5Module ๋ชจ๋“ˆ ๋“ฑ๋ก, LAZY=null ์ฒ˜๋ฆฌ
     * - ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„ ๋ฌธ์ œ ๋ฐœ์ƒ -> @JsonIgnore
     */
    @GetMapping("/api/v1/orders")
    public List<Order> ordersV1() {
        List<Order> all = orderRepository.findAllByString(new OrderSearch());

        for (Order order : all) {
            order.getMember().getName(); // Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”
            order.getDelivery().getAddress(); // Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”

            List<OrderItem> orderItems = order.getOrderItems();
            orderItems.stream().forEach(o -> o.getItem().getName()); // Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”
        }
        return all;
    }
}

์ฃผ๋ฌธ ์กฐํšŒ V2: ์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ณ€ํ™˜

OrderApiController.java

import jpabook.jpashop.domain.Address;
import jpabook.jpashop.domain.Order;
import jpabook.jpashop.domain.OrderItem;
import jpabook.jpashop.domain.OrderStatus;
import jpabook.jpashop.repository.OrderRepository;
import jpabook.jpashop.repository.OrderSearch;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequiredArgsConstructor
public class OrderApiController {

    private final OrderRepository orderRepository;

    /**
     * V1. ์—”ํ‹ฐํ‹ฐ ์ง์ ‘ ๋…ธ์ถœ
     * - Hibernate5Module ๋ชจ๋“ˆ ๋“ฑ๋ก, LAZY=null ์ฒ˜๋ฆฌ
     * - ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„ ๋ฌธ์ œ ๋ฐœ์ƒ -> @JsonIgnore
     */
    @GetMapping("/api/v1/orders")
    public List<Order> ordersV1() {
        List<Order> all = orderRepository.findAllByString(new OrderSearch());

        for (Order order : all) {
            order.getMember().getName(); // Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”
            order.getDelivery().getAddress(); // Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”

            List<OrderItem> orderItems = order.getOrderItems();
            orderItems.stream().forEach(o -> o.getItem().getName()); // Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”
        }
        return all;
    }

    **/**
     * 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(Collectors.toList());

        return result;
    }

    @Getter
    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(Collectors.toList());
        }
    }

    @Getter
    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();
        }
    }**
}

์ฐธ๊ณ : ์ง€์—ฐ ๋กœ๋”ฉ์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ์œผ๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์—†์œผ๋ฉด SQL์„ ์‹คํ–‰ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ™์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์ด๋ฏธ ๋กœ๋”ฉํ•œ ํšŒ์› ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ถ”๊ฐ€๋กœ ์กฐํšŒํ•˜๋ฉด SQL์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.