[JPA2] API개발과 고급-엔티티 직접노출(1), 엔티티DTO로 변환(2)

레몬커드요거트·2022년 11월 8일
0
post-thumbnail

ManyToOne이나 OneToOne 관계 조인 > Fetch Join
OneToMany 조회 > Collection 조회
DB에서 조회 할 때, Many만큼 줄이 증가하므로, 최적화하기 힘들다.

V1:엔티티 직접 노출

(하지만, 엔티티를 직접 노출하면 안된다.)

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
//OrderItem이 리스트로 되어 있음
package jpabook.jpashop.api;

import jpabook.jpashop.domain.Order;
import jpabook.jpashop.domain.OrderItem;
import jpabook.jpashop.repository.OrderRepository;
import jpabook.jpashop.repository.OrderSearch;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class OrderApiController {

    private final OrderRepository orderRepository;

    @GetMapping("/api/v1/orders")
    public List<Order> ordersV1(){
        List<Order> all = orderRepository.findAllByString(new OrderSearch());
        for (Order order : all) { // iter + tab > for문 만들 수 있음
            order.getMember().getName();
            order.getDelivery().getAddress();
            List<OrderItem> orderItems = order.getOrderItems();
            orderItems.stream().forEach(o->o.getItem().getName());
            /** Item명 초기화 시키는 것
             * OrderItem에는 상품명 객체 참조로 있는데,
             * LAZY이므로 강제초기화 시켜줘야함
             */
        }
        return all;
    }
}

**양방형관계는 꼭 @JsonIgnore를 걸어줘서 끊어주기..!

V2: 엔티티를 DTO로 변환

@GetMapping("/api/v2/orders")
public List<OrderDto> ordersV2(){
  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();
    orderItems= order.getOrderItems();
  }
}

!! DTO를 사용할지라도, 그대로 entity를 외부에 노출해서는 안됨 !!
-> Map을 이용해 묶기, 필요한 정보만 노출해야함.

@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()); //엔티티이므로, NULL로 반환

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

이 방식으로 필요한 정보들만 가져올 수 있으나, 지연 로딩으로 너무 많은 SQL 실행

SQL 실행 수

  • order 1번
  • member , address N번(order 조회 수 만큼)
  • orderItem N번(order 조회 수 만큼)
  • item N번(orderItem 조회 수 만큼)
profile
비요뜨 최고~

0개의 댓글