SELECT 절에 조회할 대상을 지정한다. 일반 SQL 조회는 단순히 원하는 칼럼을 조회하지만, JPA는 엔티티, 임베디드, 스칼라타입등 다양한 리턴타입이 조회대상에 올 수 있다.
*목차
1. 프로젝션 종류
2. 연관 컬렉션 조회와 한계
- 명시적 내부 조인 권장
3. 프로젝션 여러 값 조회
프로젝션 대상 : 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입)
1. 프로젝션 종류
//엔티티 프로젝션
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
왜 엔티티 프로젝션을 따로 용어로 구분지을까?
엔티티를 프로젝션 하면, 해당 결과는 엔티티 영속성에서 관리가 된다. 따라서, 값을 수정하면 영속성 컨텍스트에서 관리되기 때문에 커밋(flush)되면 더티 체킹으로 자동 반영되기 때문이다.
Member member1 = new Member();
member1.setName("memberA");
member1.setAge(15);
em.persist(member1);
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);
2. 연관 컬렉션 조회와 한계 (리스트 컬렉션)
List<Team> result = em.createQuery("select m.team from Member m", Team.class)
.getResultList();
Hibernate:
/* select
m.team
from
Member m */ select
team1_.id as id1_5_,
team1_.name as name2_5_
from
Member member0_
inner join
Team team1_
on member0_.TEAM_ID=team1_.id
단순히 m.team을 조회했을 뿐인데, 조인을 활용한 복잡한 쿼리가 나간다. 단순하더라도 우리가 작성한 JPA를 보고 따라서, 프로젝션으로 연관된 엔티티를 조회하는 것은 권장하지 않는다.
* 명시적 내부 조인 권장
List<Team> result = em.createQuery("select t from Member m join m.team t", Team.class)
.getResultList();
연관컬렉션 조회와 결과가 같다. 명시적 조인을 해야 개발자가 코드를 파악하기 쉽기 때문에 명시적 내부 조인을 권장한다.
3. 프로젝션 여러 값 조회
1. Query 타입으로 조회 ( Query query = ...)
query는 타입이 없기 때문에 가능하다. 단, Object이기 때문에 타입 캐스팅을 해야한다.
List resultList = em.createQuery("select m.name, m.age from Member m")
.getResultList();
Object o = resultList.get(0);
Object[] result = (Object[]) o;
System.out.println(result[0]);
System.out.println(result[1]);
resultList는 List가 리턴형일뿐, 어떠한 객체타입인지 모른다. 왜냐하면 Object 타입이기 때문이며, Object[]을 통해 각각 조회하고자하는 칼럼을 배열에서 꺼내야한다.
2.Object[] 타입으로 조회
List<Object[]> resultList = em.createQuery("select m.name, m.age from Member m")
.getResultList();
Object[] result = resultList.get(0);
System.out.println(result[0]);
System.out.println(result[1]);
List에 타입을 넣어줄 수 있으며, 조회시에 좀 더 코드양이 줄어들지만, 이 방법도 한계가 있다.
3. new 명령어로 조회
단순값을 DTO로 바로 조회한다.
List<MemberDto> resultList = em.createQuery("select new domain.MemberDto(m.name, m.age) from Member m")
.getResultList();
MemberDto result = resultList.get(0);
System.out.println(result.getName());
System.out.println(result.getAge());
패키지 명을 포함한 전체 클래스명을 입력하며 new로 해준다. 리턴 타입은 MemberDto으로 한다.
순서와 타입이 일치하는 생성자가 필요하다. 한계는 패키지명이 길어질수록 쿼리가 복잡해진다.
'학습 > DB' 카테고리의 다른 글
서브쿼리 (0) | 2021.10.06 |
---|---|
조인 (0) | 2021.10.06 |
경로 표현식 (0) | 2021.10.05 |
JPA에서 Dirty Check 방지하기 (0) | 2021.10.02 |
영속성 컨텍스트로 발생하는 이슈 (0) | 2021.10.01 |