이전에는 엔티티를 통해서 조회한 후에, 이걸 DTO로 변형하는 과정을 거쳤었다. 이제는 그렇게 하지말고, JPA가 DTO를 바로 조회할 수 있도록 최적화 해보자.
이를 위해 리포지에 다음의 메서드를 추가한다.
public List<OrderSimpleApiController.SimpleOrderDto> findOrderDtos(){
}
지금 문제는… 리포지가 컨트롤러를 의존하고 있다는 것임. 왜? 위의 DTO는 지금까지 연습을 위해 컨트롤러단에 임시로 이너클래스로 만들었기 때문이다. 이런일은 절대 있어선 안된다. 의존관계는 한방향으로만 흘러야 한다. 차라리 DTO를 따로 빼주자.
package jpabook.jpashop.repository;
import jpabook.jpashop.domain.Address;
import jpabook.jpashop.domain.Order;
import jpabook.jpashop.domain.OrderStatus;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class OrderSimpleQueryDto {
private Long orderId;
private String name;
private LocalDateTime orderDate;
private OrderStatus orderStatus;
private Address address;
public OrderSimpleQueryDto(Order order) {
orderId = order.getId();
name = order.getMember().getName();
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getDelivery().getAddress();
}
}
그리고 리포지 메서드를 마저 완성하자.
public List<OrderSimpleQueryDto> findOrderDtos(){
return em.createQuery(
"select o from Order o" +
" join o.member m" +
" join o.delivery d", OrderSimpleQueryDto.class) //반환타입이 DTO
.getResultList();
위 코드를 보면 알겠지만, 반환타입이 DTO이다!
그런데 사실 기본적으로는 반환타입을 DTO로 지정할 수 없다. from절의 엔티티와 일치하지 않아서… 값을 담아줄 수 없다.
따라서 이럴때는 select 절에 다음처럼 new
라는 키워드를 사용한다.
public List<OrderSimpleQueryDto> findOrderDtos(){
return em.createQuery(
"select new jpabook.jpashop.repository.OrderSimpleQueryDto() from Order o" +
" join o.member m" +
" join o.delivery d", OrderSimpleQueryDto.class)
.getResultList();
}
그리고 여기서 끝이 아니라… 생성자의 인자에 값을 줘야 한다.
이를 위해… 해당 DTO의 생성자를 손봐야 한다…