티스토리 뷰

반응형

이전에 ToOne관계는 fetch join 이후 ToMany는 지연 로딩으로 가져오는 것까지 봤다.

 

다음으로는 지연로딩으로 가져오는 과정에서 결국 query가 많이 날아가기 때문에,

ToMany또한 쿼리를 만들어서 해주는 방법이 있다.

 

public List<OrderQueryDto> findOrderQueryDtos() {
    List<OrderQueryDto> results = findOrders();

    results.forEach(o -> {
                List<OrderItemQueryDto> orderItems = findOrderItems(o.getOrderId());
                o.setOrderItems(orderItems);
            });
	return results;
}


private List<OrderItemQueryDto> findOrderItems(Long orderId){
    return em.createQuery(
        "select new jpabook.jpashop.repository.order.query.OrderItemQueryDto(oi.order.id, i.name, oi.orderPrice, oi.count) from OrderItem oi"+
        " join oi.item i"+
        " where oi.order.id = :orderId", OrderItemQueryDto.class
    ).setParameter("orderId", orderId)
    .getResultList();
}

private List<OrderQueryDto> findOrders(){
    return  em.createQuery(
                "select new jpabook.jpashop.repository.order.query.OrderQueryDto(o.id, m.name, o.orderDate, o.status, d.address) from Order o"+
                " join o.member m"+
                " join o.delivery d", OrderQueryDto.class
            ).getResultList();
}

 

다음처럼 findOrders를 가지고 ToOne관계를 먼저 만들어준 뒤에

다시 results를 roof를 돌리면서 orderItems를 다시 findOrderItems를 이용해서 채워주는 방식이다.

이렇게 하면 이전보다 쿼리가 더 적게 나가게 된다.

 

조금더 최적화하는 방법은 Map을 이용해 맵으로 변형을 한뒤 메모리에서 매칭을 해서 반환해주는 것이다.

 

public List<OrderQueryDto> findAllByDto_optimization() {
    List<OrderQueryDto> results = findOrders();

    Map<Long, List<OrderItemQueryDto>> orderItemMap = findOrderItemMap(toOrderIds(results));

    results.forEach(o -> o.setOrderItems(orderItemMap.get(o.getOrderId())));

    return results;
}

private List<Long> toOrderIds(List<OrderQueryDto> results){
    return results.stream()
    .map(o -> o.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, i.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 -> OrderItemQueryDto.getOrderId()));
}

 

마지막으로는 ToMany관계가 없는 DTO를 만들어주는 것이다.

하지만 이 방법의 경우에는 orderId가 중복으로 들어가기 때문에 페이징을 할때 원하는 기준으로 정렬이 되어 있지 않다.

 

public List<OrderFlatDto> findAllByDto_flat() {
    return em.createQuery(
        "select new jpabook.jpashop.repository.order.qeury.OrderFlatDto(o.id, m.name, o.orderDate, o.status, d.address, i.name, oi.orderprice, oi.count)"+
        " from Order o"+
        " join o.member m"+
        " join o.delivery d"+
        " join o.orderItems oi"+
        " join oi.item i", OrderFlatDto.class
    ).getResultList();
}

@Data
@AllArgsConstructor
@EqualsAndHashCode(of = "orderId")
public class OrderFlatDto {
    private Long orderId;
    private String name;
    private LocalDateTime orderDate;
    private OrderStatus orderStatus;
    private Address address;

    private String itemName;
    private int orderPrice;
    private int count;
}
728x90
반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
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
글 보관함
250x250