(JPA)JPQL 프로젝션
JPQL 프로젝션
프로젝션
- SELECT 절에 조회할 대상을 지정하는 것
- DESTINCT 로 중복 제거 가능하다.
- 대상: Entity, EmbeddedType, ScalaType
1 2 3 4
SELECT m FROM Member m // Entity 프로젝션 SELECT m.team FROM Member m // Entity 프로젝션 SELECT m.address FROM Member m // Embedded 프로젝션 SELECT m.username, m.age FROM Member m // Scala 프로젝션
엔티티 프로젝션
1
2
3
4
5
6
7
8
9
10
11
12
13
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 as m", Member.class)
.getResultList();
Member findMember = result.get(0);
findMember.setAge(20);
- 엔티티 프로젝션을 통해 SELECT 해온 결과들은 영속성 관리가 될까? 관리가 된다면
findMember.setAge(20)
을 통해Update Query
가 발생해야 한다. - 사실 처음에는 안될거라 생각했는데, 영속성 관리가 되고있다.
- 엔티티 프로젝션을 통해 SELECT 해온 결과는 모두 영속성 관리가 된다.
1
2
3
4
5
// 나쁜 예
List<Team> result = em.createQuery("select m.team from Member as m", Team.class).getResultList();
// 좋은 예
List<Team> result = em.createQuery("select t from Member as m join m.team as t", Team.class)
.getResultList();
Member
의Team
을 SELECT 한 결과도 영속성 관리가 된다. 단, 이 경우는Join Query
가 발생한다.(묵시적 조인)- 간단하게 JPQL 을 작성했는데, Join Query 가 발생되니 좋은것 같지만 JPQL 의 경우는 왠만하면 SQL과 비슷하게 작성하는것이 좋다.
나쁜 예
와좋은 예
둘 다 결과 및 발생하는 쿼리는 같지만,Join
의 경우 성능적인 측면에서 차지하는 영향이 크기 때문에 나중에 성능 개선을 위해서라도 한눈에 보이도록 작성하는것이 좋다.(명시적 조인)
임베디드 타입 프로젝션
1
2
List<Address> result = em.createQuery("select o.address from Order as o", Address.class)
.getResultList();
Order
안에 있는Embedded Type
의Address
를 조회 할 수 있다.- 소속되어있는 엔티티를 정해서 명시해줘야 하는 한계가 존재한다.
여러값 조회
- 타입이 다른 여러 필드가 나열되어 있을때, 조회하는 방법
Query
타입으로 조회
1
2
3
4
5
6
7
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("username = " + result[0]);
System.out.println("age = " + result[1]);
Query
타입으로 조회- 반환 타입이 명확하지 않아, Query 타입으로 조회
- Query 타입으로 조회 시 Object로 반환되기 때문에
Object[]
로 타입 캐스팅이 필요하다.
Type Query
로 조회
1
2
3
4
5
6
7
List<Object[]> resultList =
em.createQuery("select m.username, m.age from Member m", Object[].class).getResultList();
Object[] result = resultList.get(0);
System.out.println("username = " + result[0]);
System.out.println("age = " + result[1]);
TypeQuery
로 조회Query
타입으로 조회할때 해줘야하는 타입 캐스팅 과정을 생략할 수 있다.
new
명령어로 조회
1
2
3
4
5
6
7
8
List<MemberDto> resultList = em.createQuery(
"select new com.sutdy.hellojpql.entity.Dto.MemberDto(m.username, m.age) from Member m",MemberDto.class)
.getResultList();
MemberDto memberDto = resultList.get(0);
System.out.println("username = " + memberDto.getUsername());
System.out.println("age = " + memberDto.getAge());
단순 값을 DTO로 바로 조회 할 수 있다.
- 패키지 명을 포함한 전체 클래스 명을 입력해줘야 한다.
- 패키지 명이 길어지면 코드도 지저분해지는 단점이 있다.(QueryDSL을 사용하면 극복 가능)
- 순서와 타입이 일치하는 생성자가 필요하다.
REFERENCE
#JPA_JPQL_프로젝션
This post is licensed under CC BY 4.0 by the author.