orders를 가져오는 것 까지는 똑같고 orderItems를 가져올 때 in 을 이용해서 한번에 가져오는 것이다.
그런 다음 메모리(애플리케이션)에서 값을 매칭 해주는 식이다.
public List<OrderQueryDTO> findAllByDTO_optimization() {
List<OrderQueryDTO> orders = findOrders();
Map<Long, List<OrderItemQueryDTO>> orderItemMap = findOrderItemMap(toOrderIds(orders));
orders.forEach(o -> o.setOrderItems(orderItemMap.get(o.getOrderId())));
return orders;
}
private List<Long> toOrderIds(List<OrderQueryDTO> orders) {
return orders.stream()
.map(OrderQueryDTO::getOrderId)
.collect(Collectors.toList());
}
private Map<Long, List<OrderItemQueryDTO>> findOrderItemMap(List<Long> orderIds) {
List<OrderItemQueryDTO> orderItems = em.createQuery("select new jpabook.jpashop.repository.order.query.OrderItemQueryDTO(oi.order.id, oi.item.name, oi.orderPrice, oi.count) from OrderItem oi" +
" join oi.item i" +
" where oi.order.id in :orderIds", OrderItemQueryDTO.class)
.setParameter("orderIds", orderIds)
.getResultList();
return orderItems.stream()
.collect(Collectors.groupingBy(OrderItemQueryDTO::getOrderId));
}
총 2번의 쿼리가 날아간다.
ToOne은 최대한 한번에 가져온다.
많은 코드를 직접 이렇게 파싱 하기가 마냥 쉽지 않다는 생각이 든다.