Post

(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();
  • MemberTeam 을 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 TypeAddress 를 조회 할 수 있다.
  • 소속되어있는 엔티티를 정해서 명시해줘야 하는 한계가 존재한다.

여러값 조회

  • 타입이 다른 여러 필드가 나열되어 있을때, 조회하는 방법
  1. 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[] 로 타입 캐스팅이 필요하다.
  1. 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 타입으로 조회할때 해줘야하는 타입 캐스팅 과정을 생략할 수 있다.
  1. 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.