JPQL 결과 조회
참고
JPQL 반환 타입
- EntityManager의 createQuery()는 두 가지의 리턴 타입이 있다.
- Query
- 반환 타입이 명확하지 않은 경우에 잡힌다.
- TypedQuery
- 반환 타입이 명확한 경우
- createQuery()의 두 번째 인자로 타입을 넘겨준 경우에 그 타입으로 반환 타입이 잡힌다.
- Query
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();
- 결과를 리스트로 받는다.
- 결과가 없으면 빈 리스트로 준다.
- getSingleResult();
파라미터 바인딩
- 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.