프레임워크(Framework)/JPA

[JPA] JPQL 프로젝션(Projection) - 객체지향 쿼리 언어 JPQL (2)

잇트루 2022. 12. 14. 00:09
반응형
본 내용은 온라인 강의 사이트 인프런의 김영한 님의 강의 내용이 포함되어 있습니다.
'자바 ORM 표준 JPA 프로그래밍 - 기본편'
 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

프로젝션

프로젝션은 JPQL의 SELECT 절에 조회할 대상을 지정하는 것을 의미한다.

SELECT 절의 조회 대상의 타입에 따라 프로젝션의 종류가 다르다.

 

프로젝션 대상

  • 엔티티
SELECT m FROM Member m
SELECT m.team FROM Member m

 

  • 임베디드 타입
SELECT m.address FROM Member m

 

  • 스칼라 타입(숫자, 문자 등 기본 데이터 타입)
SELECT m.username, m.age FROM Member m

 

엔티티 프로젝션

엔티티 프로젝션은 SELECT 절의 조회 대상이 엔티티 객체인 경우를 말한다.

List<Member> result = em.createQuery("select m from Member m", Member.class).getResultList();

 

엔티티 프로젝션의 특징

Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);

em.flush();
em.clear();

List<Member> result = em.createQuery("select m from Member m", Member.class).getResultList();

Member findMember = result.get(0);
findMember.setAge(20);

다음과 같이 영속성 컨텍스트가 완전히 비어있는 상태에서 엔티티 프로젝션의 조회를 할 경우 쿼리 결과를 통해 엔티티의 속성을 변경할 수 있다.

 

즉, 엔티티 프로젝션의 경우 영속성 컨텍스트에서 관리되는 것을 의미한다.

 

 

임베디드 타입 프로젝션

임베디드 타입 프로젝션은 SELECT 절의 조회 대상이 엔티티의 값 타입 속성인 경우를 말한다.

List<Address> resultList = em.createQuery("select m.address from Member m", Address.class).getResultList();
  • 임베디드 값 타입은 특정 엔티티에 속해있기 때문에 조회의 시작점이 될 수 없다.
    • select a from address a와 같은 쿼리가 불가능하다.

 

 

스칼라 타입 프로젝션

스칼라 타입 프로젝션은 SELECT 절의 조회 대상이 데이터 타입과 상관없이 여러 데이터를 조회하는 경우를 말한다.

List resultList = em.createQuery("select m.username, m.age from Member m").getResultList();
  • username은 String 타입, age는 int 타입이다.
  • 이 경우 결과 데이터를 조회하기 위한 여러 방법이 존재한다.

 

타입 캐스팅을 이용한 Object[] 조회

List resultList = em.createQuery("select m.username, m.age from Member m").getResultList();

// 타입 캐스팅
Object o = resultList.get(0);
Object[] result = (Object[]) o;

System.out.println("result[0] = " + result[0]);
System.out.println("result[0] = " + result[1]);
  • 조회된 결과 List에는 Object 타입으로 저장된다.
  • 따라서, 각각의 username과 age를 조회하기 위해서는 배열로 캐스팅해야 한다.

 

List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m").getResultList();

Object[] result = resultList.get(0);
System.out.println("result[0] = " + result[0]);
System.out.println("result[0] = " + result[1]);
  • 위와 같이 제네릭을 활용하여 타입 캐스팅이 가능하다.

 

new 명령어를 통한 DTO 조회

MemberDTO 생성

@Getter
@Setter
@AllArgsConstructor
public class MemberDTO {

    private String username;
    private int age;

}

 

단순 값을 DTO로 바로 조회할 수 있다.

List<MemberDTO> result = em.createQuery("select new jpql.MemberDTO(m.username, m.age) from Member m", MemberDTO.class)
                    .getResultList();

MemberDTO memberDTO = result.get(0);
System.out.println("memberDTO = " + memberDTO.getUsername());
System.out.println("memberDTO = " + memberDTO.getAge());
  • SELECT 절에 패키지 명을 포함하여 전체 클래스 명을 입력한다.
  • 순서와 타입이 일치하는 생성자가 필요하다.
  • 패키지명을 작성해야 하는 불편함은 QueryDSL을 사용하여 극복할 수 있다.
반응형