[JPA] 프로젝션

정의

  • select 문에서 특정 데이터를 선택하여 조회하는 행위
  • JPQL 에서 프로젝션사용시
    1. 원하는 엔티티
    1. 임베디드 타입
    1. 스칼라 타입 ⇒ 기본 데이터 타입 말하는겨 ㅇㅇ

엔티티 프로젝션

  • 쿼리의 결과로 엔티티를 직접 반환함
  • 별건 없고
    • 회원 엔티티 조회
      SELECT m FROM Member m
    • 회원의 속한 팀 엔티티 조회
      SELECT m.team FROM Member m

임베디드 타입 프로젝션

  • 엔티티 내부에 포함된 복합 값 타입을 간접적으로 조회
  • 임베디드 타입을 잘못 조회하는 경우
    SELECT a FROM Address a // 오류, Address는 엔티티가 아니므로 시작점으로 사용될 수 없음
  • 올바른 경우
    • 엔티티를 통한 임베디드 조회
      String query = "SELECT o.address FROM Order o";
      List<Address> addresses = em.createQuery(query, Address.class).getResultList();
    • 실행된 SQL
      SELECT order.city, order.street, order.zipcode FROM Orders order
  • 임베디드 타입은 값 타입으로 영속성 컨텍스트에서 관리 X → 엔티티 조회후 간접 호출해야함

스칼라 타입 프로젝션

  • 숫자 문자열 같은 기본 데이터 타입을 조회
  • 이름 조회
    SELECT m.username FROM Member m
  • 나이 조회
    SELECT m.age FROM Member m
  • 이런 단순 값은 영속성 컨텍스트에 의해 관리되지 않아요

여러 값의 조회

@Test
    void findMemberVaryData() {
        List<Object[]> resultList1 = em.createQuery("select m.name , m.name from Member m")
                                       .getResultList();
        
        for (Object[] objects : resultList1) {
            System.out.println("name = " + objects[0]);
            System.out.println("age = " + objects[1]);
        }
    }
  • 필요한 특정 데이터만 선택하여 조회할 필요가 있는 경우
    • TypedQuery 대신에 Query 객체를 사용해야한다.
  • 주의
    1. 영속성 컨텍스트 관리
      1. 조회된 엔티티는 영속성 컨텍스트에 의해 관리됨
      1. 하지만
      1. 스칼라 값은 값 타입이라 관리되지 않음
    1. 가독성의 문제
      1. 쿼리 결과를 처리하는 코드에서 명확한 타입 정보가 없음
      1. 코드의 가독성이 떨어진다.
      1. 개선방안
        1. DTO 를 사용하여 결과를 감싸야 합니다.

NEW 명령어의 사용

  • 개요
    • JPQL NEW 명령어는 조회한 결과를 사용자 정의 클래스의 인스턴스로 직접 매핑할 때 사용
    • 특정 클래스의 객체로 바로 받아 처리가 가능
      • 별도 객체 변환 작업을 줄여줌
  • 코드
    @Test
        void newFunctionQuery() {
            TypedQuery<MemberDTO> query = em.createQuery(
                "select new com.example.springboot3.test.MemberDTO(m.name, m.age) from Member m", MemberDTO.class
            );
            List<MemberDTO> resultList = query.getResultList();
            System.out.println("resultList = " + resultList);
        }
    • Record ~= DTO
    public record MemberDTO(String name, int age) {
    } // java 17 만 가능
    • new 명령어를 사용해 JPQL 쿼리 결과를 직접 매핑함.
    • 쿼리 결과와 일치하는 생성자를 가져야 매핑이 됩니다.
    • 주의
      1. 전체 클래스명을 명기해야합니다
      1. 타입과 타입결과 순서에 맞는 생성자가 반드시 존재해야합니다.


Uploaded by N2T

'자바 > JPA' 카테고리의 다른 글

[JPA] JPQL 의 기본 문법과 쿼리 API  (0) 2023.11.09
[JPA] JPQL 파라미터 바인딩  (0) 2023.11.09
[JPA] 페이징 API  (0) 2023.11.09
[JPA] 집합 함수  (0) 2023.11.09
[JPA] JPQL 조인  (0) 2023.11.09