JPA : JPA를 DTO로 바로 접근하기

    JPA가 DTO로 직접 접근

    기본적으로 DTO로 직접 접근하기 위해서는 new 연산자를 사용해 DTO를 만들어서 반환해줘야한다. 따라서 반환 타입을 Dto.class로 하고, new 연산자로 DTO를 만들어주면 된다. 약간 뜬구름 잡는 거 같은데, 좀 더 상세하게 알아보자.

     

    첫번째 방법, Root Alias를 넘기기 → 실패

    public List<SimpleQueryDto> findOrderDtos() {
    
        
        return em.createQuery("select new hellojpa.jpa.repository.order.simplequery.SimpleQueryDto(o)" +
                        " from Order o" +
                        " join o.member m" +
                        " join o.delivery d", SimpleQueryDto.class)
                .getResultList();
    }

    Root Alias를 넘기는 방법을 고민해봤다.

    1. Root Alias에 필요한 Member, Delivery Table을 Join해서 가져온다.
    2. Root Alias를 생성자에 넘긴 후, 생성자를 통해 생성해본다.

    위의 방법은 실패했다. Bean Serialization 에러가 발생했기 때문이다. 발생하는 이유는 Member와 Delivery가 Lazy Loading으로 설정되어 이들이 프록시 객체이기 떄문이다. 따라서 이 프록시 상태를 해소시켜줘야지 JPA가 DTO로 바로 접근할 수 있다. 

     

     

    두번째 방법, Fetch Join으로 한번에 가져오기 → 실패

    public List<SimpleQueryDto> findOrderDtos() {
    
        return em.createQuery("select new hellojpa.jpa.repository.order.simplequery.SimpleQueryDto(o)" +
                        " from Order o" +
                        " join fetch o.member m" +
                        " join fetch o.delivery d", SimpleQueryDto.class)
                .getResultList();
    }

    Lazy Loading이 문제기 때문에 Fetch Join으로 필요한 것들을 한번에 가져오면 된다고 판단했다. 따라서 Fetch Join으로 값을 가져와 Root Alias를 넘겨봤다.

    넘기자마자 바로 다음과 같은 에러가 난다. fetch join을 사용할 경우 Root Alias가 반드시 Select 절에 있어야 한다는 것이다. 그렇지만 new DTO를 하는 입장에서는 그렇게 사용할 수 없다. 따라서 fetch Join으로 Lazy Loading을 해소하는 방법은 불가능하다.

     

    세번째 방법, Fetch Join으로 한번에 가져오기 → 성공

    public List<SimpleQueryDto> findOrderDtos() {
    
        return em.createQuery("select new hellojpa.jpa.repository.order.simplequery.SimpleQueryDto(o.id, m.name, o.orderDate, o.status, d.address)" +
                        " from Order o" +
                        " join o.member m" +
                        " join o.delivery d", SimpleQueryDto.class)
                .getResultList();
    }

    정확하지는 않은데 다음과 같이 나는 이해했다. 

    프록시 상태를 해결해주기 위해 프로퍼티로 접근했다. Join한 Table을 가져오면 기본적으로 Member, Delivery에 대한 참조값은 비어있다. 즉, 프록시 객체 상태이다. JPA는 프록시 객체의 프로퍼티에 접근하게 되면, 프록시 상태가 다 해소가 되게 된다. 따라서 정상적으로 DTO로 접근해서 만들 수 있게 된다.

     

    댓글

    Designed by JB FACTORY