Post

JPQL 결과 조회





참고



JPQL 반환 타입

  • EntityManager의 createQuery()는 두 가지의 리턴 타입이 있다.
    • Query
      • 반환 타입이 명확하지 않은 경우에 잡힌다.
    • TypedQuery
      • 반환 타입이 명확한 경우
      • createQuery()의 두 번째 인자로 타입을 넘겨준 경우에 그 타입으로 반환 타입이 잡힌다.


1
2
3
4
5
6
7
// 반환 타입을 넘겨준 경우
TypedQuery typedQuery = em.createQuery("SELECT b FROM Book b", Book.class);

// 반환 타입이 명확하지 않아 인자로 넘겨주지 않은 경우
Query query = em.createQuery("SELECT b.title, b.price FROM Book b");





결과 조회

  • Query 또는 TypedQuery 타입을 실행 시켜 결과를 받아와야 한다.
  • 결과 조회 api에는 자주 쓰이는 두 가지가 있다.
    • getSingleResult();
      • 하나의 결과값을 받음.
      • 쿼리의 결과가 정확히 하나여야 한다. 아니면 예외가 발생한다.
        • 결과가 없으면, javax.persistence.NoResultException
        • 결과가 2개 이상이면, javax.persistence.NonUniqueResultException
    • getResultList();
      • 결과를 리스트로 받는다.
      • 결과가 없으면 빈 리스트로 준다.





파라미터 바인딩

  • JPQL을 사용한 쿼리 객체는 setParameter() 메서드를 사용해서 파라미터 바인딩을 해줄 수 있다.
  • 파라미터 바인딩은 두 가지 방식이 있다.
    • 이름 기준
    • 위치 기준


1
2
3
4
5
6
7
8
9
// 이름 기준
em.createQuery("SELECT b FROM Book b WHERE b.title = :title")
    .setParameter("title", "babo book");

// 위치 기준
em.createQuery("SELECT b FROM Book b WHERE b.title = ?1")
    .setParameter(1, "babo book")


  • 사용법은 위와 같다.
  • 위치 기준은 권장되지 않는다.
    • 파라미터가 늘어나서 순서가 꼬이면 숫자를 바꿔준다거나 하는 일이 생기니까-



파라미터 바인딩 꼭 써야 하나요

  • 그냥 JPQL 스트링에 값을 직접 넣어도 잘 동작한다.
  • 그런데 왜 성가시게 저걸 써야할까
  • 크게 두 가지 이유가 있다.





프로젝션

  • select 절에서 조회할 대상을 지정하는 것을 말한다.
  • 프로젝션의 대상은 다음과 같다.
    • 엔티티 프로젝션
    • 임베디드 타입 프로젝션
    • 스칼라 타입 프로젝



엔티티 프로젝션

1
2
3
4
List<Bookshelf> resultList = em.createQuery("SELECT bs FROM Bookshelf bs", Bookshelf.class)
    .getResultList();

  • 기본적인 엔티티 조회 쿼리이다.
  • 결과로 엔티티의 리스트를 받아온다.


1
2
3
4
List<Book> resultList = em.createQuery("SELECT bs.bookList FROM Bookshelf bs", Book.class)
    .getResultList();

  • 연관 관계 엔티티를 조회하는 쿼리이다.
  • 결과로 연관 관계 엔티티의 리스트를 받아온다.



임베디드 타입 프로젝션

1
2
3
4
List<RentalPeriod> resultList = em.createQuery("SELECT b.rentalReriod FROM Book b", RentalPeriod.class)
    .getResultList();

  • 엔티티의 임베디드 값 타입을 조회하는 쿼리이다.
  • 임베디드 값 타입으로 결과를 받아온다.



스칼라 타입 프로젝션

1
2
3
4
List<String> resultList = em.createQuery("SELECT b.title FROM Book b", String.class)
    .getResultList();

  • 하나의 기본 값 타입을 조회하는 쿼리이다.
  • 조회 컬럼이 하나라면 기본 값 타입으로 결과로 받아볼 수 있다.

Object로 조회

1
2
3
4
5
6
7
8
9
10
List resultList = em.createQuery("SELECT b.title, b.price FROM Book b")
    .getResultList();

for(Object result : resultList) {
    Object[] o = (Object[]) result;

    souf("title= %s, price= %d \n", o[0], o[1]);
}

  • 2개 이상의 기본 값 타입을 조회하는 쿼리이다.
  • 여기서는 createQuery()의 리턴값을 Query로 받는다.
    • 결과 역시 raw 타입 리스트로 받는다.


Object[]로 조회

1
2
3
4
5
6
7
8
List<Object[]> resultList = em.createQuery("SELECT b.title, b.price FROM Book b", Object[].class)
    .getResultList();

    for(Object[] o : resultList) {
        souf("title= %s, price= %d \n", o[0], o[1]);
    }

  • 이렇게 TypedQuery를 사용하는 방법도 있다.


DTO로 조회

1
2
3
4
5
6
7
8
@Getter
@AllArgsConstructor
class BookInfoDto {
    private String title;
    private int price;
}

1
2
3
4
List<BookInfoDto> resultList = em.createQuery("SELECT new me.bogeun.dto.BookInfoDto(b.title, b.price) FROM Book b", BookInfoDto.class)
    .getResultList();

  • 위에 처럼 조회할 컬럼의 타입에 맞는 DTO를 만들어 조회하는 방법이다.
  • JPQL에는 new 연산자를 사용한다.
    • DTO 클래스의 FQCN을 적어줘야 한다.
    • DTO 클래스에는 적합한 생성자 함수가 정의돼야 한다.





This post is licensed under CC BY 4.0 by the author.