[JPA] JPQL - 프로젝션
12 Aug 2022해당 포스트는 인프런 김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 을 듣고 정리한 글입니다.
JPQL - 프로젝션
개요
- SELECT 절에 조회할 대상을 지정하는 것
- 프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자등 기본 데이터 타입)
- DISTINCT로 중복 제거
- 엔티티 프로젝션
- SELECT m FROM Member m
JPQL은 createQuery로 영속성에 넣어주는지 확인해 보자.
/* 프로젝션 */
List<Member> members = entityManager.createQuery("SELECT m from Member m", Member.class)
.getResultList();
Member findMember = members.get(0);
findMember.setAge(30);
/* update
com.dhaudgkr.jpa07.jpql02.domain.Member */ update
Member
set
age=?,
TEAM_ID=?,
username=?
where
id=?
업데이트 쿼리가 나가는것을 보아 영속성 컨텍스트에 Member를 담는 것을 알 수 있다.
- SELECT m.team FROM Member m
Member에 있는 Team을 가져올때는 어떻게 가져와야 할까?
List<Team> teams = entityManager.createQuery("SELECT m.team from Member m", Team.class)
.getResultList();
/* SELECT
m.team
from
Member m */ select
team1_.id as id1_3_,
team1_.age as age2_3_,
team1_.username as username3_3_
from
Member member0_
inner join
Team team1_
on member0_.TEAM_ID=team1_.id
이렇게 하면 자동으로 join이 되어 나가지만 권장하지는 않다. JPQL은 최대한 나가는 쿼리와 비슷하게 작성해야 한다.
임베디드 타입 프로젝션
- SELECT m.address FROM Member m
entityManager.createQuery("SELECT o.address from Order o", Address.class)
.getResultList();
/* SELECT
o.address
from
Order o */ select
order0_.city as col_0_0_,
order0_.street as col_0_1_,
order0_.zipcode as col_0_2_ from
ORDERS order0_
임베디드 타입은 무난히 가져오는 것을 볼 수 있다.
하지만 Address를 테이블로 지정해서 가져오는것은 할 수 없다.
- 잘못된 예시
entityManager.createQuery("SELECT a from Address a", Address.class)
.getResultList();
스칼라 타입 프로젝션
- SELECT m.username, m.age FROM Member m
entityManager.createQuery("SELECT m.username, m.age from Member m")
.getResultList();
/* SELECT
m.username,
m.age
from
Member m */ select
member0_.username as col_0_0_,
member0_.age as col_1_0_
from
Member member0_
여러 값 조회
- SELECT m.username, m.age FROM Member m
- Query 타입으로 조회
/* Object */
List objectList = entityManager.createQuery("SELECT m.username, m.age from Member m")
.getResultList();
Object o = objectList.get(0);
Object[] objects = (Object[]) o;
System.out.println("objects.username : " + objects[0]);
System.out.println("objects.age : " + objects[1]);
/* SELECT
m.username,
m.age
from
Member m */ select
member0_.username as col_0_0_,
member0_.age as col_1_0_
from
Member member0_
objects.username : member1
objects.age : 10
- Object[] 타입으로 조회
/* Object[] */
List<Object[]> results = entityManager.createQuery("SELECT m.username, m.age from Member m")
.getResultList();
Object[] objects = results.get(0);
System.out.println("objects.username : " + objects[0]);
System.out.println("objects.age : " + objects[1]);
/* SELECT
m.username,
m.age
from
Member m */ select
member0_.username as col_0_0_,
member0_.age as col_1_0_
from
Member member0_
objects.username : member1
objects.age : 10
- new 명령어로 조회
- 단순 값을 DTO로 바로 조회 SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m
- 패키지 명을 포함한 전체 클래스 명 입력
- 순서와 타입이 일치하는 생성자 필요
/* new */
List<MemberDto> result = entityManager.createQuery("SELECT new com.dhaudgkr.jpa07.jpql02.domain.MemberDto(m.username, m.age) from Member m", MemberDto.class)
.getResultList();
MemberDto memberDto = result.get(0);
System.out.println("MemberDto.username : " + memberDto.getUsername());
System.out.println("MemberDto.age : " + memberDto.getAge());
/* SELECT
new com.dhaudgkr.jpa07.jpql02.domain.MemberDto(m.username,
m.age)
from
Member m */ select
member0_.username as col_0_0_,
member0_.age as col_1_0_
from
Member member0_
MemberDto.username : member1
MemberDto.age : 10