주문조회 추가 v1&v2

JIWOO YUN·2023년 9월 14일
0
post-custom-banner

주문 내역에서 추가로 주문한 상품 정보를 추가로 조회하는 경우

Order기준으로 OrderItem과 Item 이 필요함.

order 엔티티에 OrderItems와 OneToMany 관계이다. - 컬렉션 조회 최적화를 통해서 성능을 최적화 해보자.

엔티티 직접노출의 경우

이전에 간단한 주문조회와 마찬가지로 findAllByString을 통해서 전체 조회를 진행한다.

Lazy로딩 문제가 발생했던 것은 이전 해결법과 마찬가지로 강제초기화를 통해 진행

    @GetMapping
    public List<Order> ordersV1(){
        List<Order> all = orderRespository.findAllByString(new OrderSearch());
        //간단한조회와 마찬가지로 Lazy강제초기화 진행
        for (Order order : all) {
            order.getMember().getName();
            order.getDelivery().getAddress();
            List<OrderItem> orderItems = order.getOrderItems();
            //람다식으로 강제초기화
            orderItems.stream().forEach(o->o.getItem().getName());
        }
        return all;

    }

양방향 연관관계일 경우 @JsonIgnore를 통해서 무한루프가 걸리지 않게 한곳에 적어줘야함.

하지만 잊으면 안된다. 엔티티 직접 노출을 해버리면 엔티티 스펙이 바뀌면 이 코드가 제대로 돌아가지 않게 된다.


주문조회 v2 - DTO로 변환해서 넘기자.

orderApiController내부에 orderDto를 생성하고 실행 하게 되면 orderItem은 null로 나오지 않게 된다.

    @Data
    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.getOrderStatus();
            address = order.getDelivery().getAddress();
            orderItems = order.getOrderItems();
        }

    }
{
    "data": [
        {
            "id": 1,
            "member": {
                "id": 1,
                "name": "userA",
                "address": {
                    "city": "서울",
                    "street": "1",
                    "zipcode": "1111"
                }
            },
            "orderItems": null,
            "delivery": {
                "id": 1,
                "address": {
                    "city": "서울",
                    "street": "1",
                    "zipcode": "1111"
                },
                "status": null
            },
            "orderDate": "2023-09-14T17:05:27.974346",
            "orderStatus": "ORDER",
            "totalPrice": 50000
        }

    ]
}

Why? orderItem은 entity기 때문에 null로 나오는 것이다.

  • OrderItem이 지연로딩에 해당되기 때문에 내부안에있는 값을 불러오지 않는다면 프록시 객체로 채워져 있기 때문에 null로 반환이 된다고 이해했다.

그렇기 때문에 OrderItemsDto를 또 따로 만들어서 람다식을 통해서 다시 변환해주는 형식을 사용한다.

그냥 OrderItem 리스트를 stream으로 변환을 하게 되면 이것도 엔티티 노출이 발생하게 되니 또 따로 OrderItemsDto를 만들고 변환을 해야한다.

    @Data
    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.getOrderStatus();
            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();
        }
    }

하지만 이렇게 할 경우 N+1문제가 발생한다.

order 조회때 1번

member,address때 N번(order 조회에서 나온 결과만큼)

orderItem찾을때 n번 (order 조회에서 나온 결과 개수만큼)

item N번 쿼리 발생으로 엄청난 쿼리 수 발생


번외

@Data 는 만들어주는게 너무 많기 때문에 사용하지 않는게 좋을 수도 있다. -> getter와 setter는 물론이고 다른것도 꽤 많이 만들어짐.따라 들어가보면

Getter, Setter, RequiredArgsConstructor, ToString, EqualsAndHashCode, Value

밑의 이만큼의 어노테이션을 넣어주는 어노테이션이다. -> 그렇기 때문에 무지성 @Data를 쓰는 건 좋지 않다고 한다.


profile
열심히하자
post-custom-banner

0개의 댓글