@RestController
@RequiredArgsConstructor
public class OrderSimpleApiController {
private final OrderRepository orderRepository;
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> orderV2(){
List<Order> orders = orderRepository.findAllByString(new OrderSearch());
List<SimpleOrderDto> result =
orders.stream().map(SimpleOrderDto::fromEntity).collect(Collectors.toList());
return result;
}
// Entity를 Dto로 변환하는 방법중
// Record(Data Class)를 사용했습니다
public record SimpleOrderDto(
Long orderId,
String name,
LocalDateTime orderDate,
OrderStatus orderStatus,
Address address
){
public static SimpleOrderDto fromEntity(
Order order
){
return new SimpleOrderDto(
order.getId(),
order.getMember().getName(), // Lazy 초기화
order.getOrderDate(),
order.getStatus(),
order.getDelivery().getAddress() // Lazy 초기화
);
}
}
}
Entity를 직접 노출하는 것은 매우 매우 좋지 않기 때문에 Dto 클래스로 변환 후 화면에 노출시켜야 한다. Dto로 변환할 경우 데이터 베이스에 테이블이 변경되도 API 스펙에는 영향을 주지 않기 때문에 Dto로 변환해서 사용해야 한다.
1 + N + N
번 실행된다.order
조회 1번 (order 조회결과 수가 N이 된다.)order -> member
지연로딩 조회 N번order -> delivery
지연로딩 조회 N번order
의 결과가 4개일 경우 최악의 경우 1 + 4 + 4
번 실행된다. public List<Order> findAllWithMemberDelivery(OrderSearch orderSearch) {
return em.createQuery("select o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d", Order.class)
.getResultList();
}
@GetMapping("/api/v3/simple-orders")
public List<SimpleOrderDto> orderV3(){
List<Order> orders = orderRepository.findAllWithMemberDelivery(new OrderSearch());
List<SimpleOrderDto> result =
orders.stream().map(SimpleOrderDto::fromEntity).collect(Collectors.toList());
return result;
}
select
order0_.order_id as order_id1_6_0_,
member1_.memer_id as memer_id1_4_1_,
delivery2_.delivery_id as delivery1_2_2_,
order0_.delivery_id as delivery4_6_0_,
order0_.member_id as member_i5_6_0_,
order0_.order_date as order_da2_6_0_,
order0_.status as status3_6_0_,
member1_.city as city2_4_1_,
member1_.street as street3_4_1_,
member1_.zipcode as zipcode4_4_1_,
member1_.name as name5_4_1_,
delivery2_.city as city2_2_2_,
delivery2_.street as street3_2_2_,
delivery2_.zipcode as zipcode4_2_2_,
delivery2_.status as status5_2_2_
from
orders order0_
inner join
member member1_
on order0_.member_id=member1_.memer_id
inner join
delivery delivery2_
on order0_.delivery_id=delivery2_.delivery_id
Fetch Join 을 사용할 경우 쿼리를 한번만 조회하면 되기 때문에 성능상 훨씬 좋다.