API 개발 고급 - 컬렉션 조회 최적화 1
주문내역에서 추가로 주문한 상품 정보를 추가로 조회하자.
Order 기준으로 컬렉션인 OrderItem과 Item이 필요하다.
앞에 예제에는 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번 나간다..
댓글남기기