1 분 소요

주문내역에서 추가로 주문한 상품 정보를 추가로 조회하자. Order 기준으로 컬렉션인 OrderItemItem이 필요하다.

앞에 예제에는 toOne 관계만 있었다. 이번에는 컬렉션인 일대다 관계 (oneToMany)를 조회하고, 성능 을 최적화 해보자

1. v1 엔티티 직접 노출

1
2
3
4
5
6
7
8
9
10
11
@GetMapping("/api/v1/orders")  
public List<Order> ordersV1() {  
    List<Order> all = orderRepository.findAllByString(new OrderSearch());  
    for (Order order : all) {  
        order.getMember().getName();  
        order.getDelivery().getAddress();  
        List<OrderItem> orderItems = order.getOrderItems();  
        orderItems.stream().forEach(o -> o.getItem().getName());  
    }  
    return all;  
}

2. v2 엔티티를 DTO로 변환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@GetMapping("/api/v2/orders")  
public List<OrderDto> orderV2() {  
    List<Order> orders = orderRepository.findAllByString(new OrderSearch());  
    List<OrderDto> collect = orders.stream()  
            .map(o -> new OrderDto(o))  
            .collect(Collectors.toList());  
    return collect;  
  
}  
  
@Getter  
static class OrderDto {  
  
    private Long orderId;  
    private String name;  
    private LocalDateTime orderDate;  
    private OrderStatus orderStatus;  
    private Address address;  
    private List<OrderItem> orderItems;  
  
    public  OrderDto(Order order) {  
        orderId = order.getId();  
        name = order.getMember().getName();  
        orderDate = order.getOrderDate();  
        orderStatus = order.getStatus();  
        address = order.getDelivery().getAddress();  
        order.getOrderItems().stream().forEach(o -> o.getItem().getName());  
        orderItems = order.getOrderItems();  
    }  
}

잘 나오긴 하는데 private List<OrderItem> orderItems; 이게 DTO에서 엔티티를 가지고 있기 때문에 수정이 필요하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@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();  
    }  
}

이렇게 한번 더 래핑을 해서 orderItemDto를 OrderDto에서 사용하도록 수정해야 한다.

이제 필요한 데이터만 가져올 수 있게 되었다..

엔티티를 외부로 노출하지 말라 라는 말이 단순하게 껍데기만 DTO로 노출 시키라는게 아니라 정말 그 속 (DTO) 에 있는 것까지 다 노출(orderItem) 하면 안된다. 단 Value Object는 상관 없다. 뭐 값이 바뀌고 그러진 않으니깐

자 근데 이제 쿼리가 몇 개 나가는지 보자..

… 먼저 오더 1 > 멤버 > 딜리버리 > 오더 아이템 > 아이템 (아이템이 2개니깐 2번~) 오더 2 .. > 이렇게 쿼리가 12번 나간다..

업데이트:

댓글남기기