2024. 1. 24. 23:08ㆍspring/JPA
SELECT 절에 조회할 대상을 지정하는 것을 프로젝션이라 한다. 프로젝션 대상은 다음과 같다.
1. 엔티티
2. 엠비디드 타입
3. 스칼라 타입이(숫자, 문자 등 기본 데이터)
엔티티 프로젝션
SELECT m FROM Member m //회원
SELECT m.team FROM Member m // 팀
위 두 쿼리는 모두 엔티티를 프로젝션 대상으로 사용했다. 객체를 바로 조회한 것인데 컬럼을 하나하나 나열해서 조회해야 하는 SQL과 차이가 있다. 이렇게 조회된 엔티티는 영속성 컨텍스트에서 관리된다.
임베디드 타입 프로젝션
JPQL에서 임베디드 타입은 엔티티와 거의 비슷하게 사용된다.
(임베디드 타입은 조회의 시작점이 될 수 없다.) => 테이블이 아니기 때문
아래 코드는 잘못된 예이다.
SELECT a FROM Address a
Order 엔티티에 임베디드 되어있기 때문에 Order 엔티티로 시작점을 잡아야 한다.
SELECT o.address FROM Order o
임베디드 타입은 엔티티 타입이 아닌 값 타입이다. 그렇기 때문에 영속성 컨텍스트에서 관리되지 않는다.
스칼라 타입 프로젝션
숫자, 문자, 날짜와 같은 기본 데이터 타입들을 스칼라 타입이라 한다.
List<String> resultList =
em.createQuery("select m.name from Member m", String.class)
.getResultList();
여러 값 조회
엔티티를 대상으로 조회하면 편리하겠지만, 꼭 필요한 데이터들만 선택해서 조회해야 할 때도 있다.
프로젝션에 여러 값을 선택하면 TypeQuery를 사용할 수 없고 대신에 Query를 사용해야 한다.
Query query =
em.createQuery("SELECT m.name, m.age FROM Member m");
List resultList = query.getResultList();
여기서 List의 원소 타입은 Object인데 name, age 값이 이 Object 인스턴스에 배열 형태로 들어가 있기 때문에 형변환을 해줘야 한다.
Iterator iterator = resultList.iterator();
while(iterator.hasNext()) {
//형변환 필요!
Object[] row = (Object[]) iterator.next();
String name = (String) row[0];
Integer age = (Integer) row[1];
}
제네릭에 Object[] 를 사용하면 조금 더 간결하게 개발할 수 있긴 하다.
Query query =
em.createQuery("SELECT m.name, m.age FROM Member m");
List<Object[]> resultList = query.getResultList();
for (Object[] row : resultList) {
String name = (String) row[0];
Integer age = (Integer) row[1];
}
NEW 명령어
name, age 두 필드를 프로젝션해서 타입을 지정할 수 없으므로 TypeQuery를 사용할 수 없다. 하지만 DTO 객체를 만들어 변환해서 사용할 수 있다.
public class UserDTO {
private String name;
private int age;
public UserDTO(String name, int age) {
this.name = name;
this.age = age;
}
//...
}
TypeQuery<UserDTO> query =
em.createQuery("SELECT new jpastudy.jpql.UserDTO(m.name, m.age)
FROM Member m", UserDTO.class);
List<UserDTO> resultList = query.getResultList();
SELECT 다음에 NEW 명령어를 사용하면 반환받을 클래스를 지정할 수 있는데 이 클래스의 생성자에 JPQL 조회 결과를 넘겨줄 수 있다.
그리고 NEW 명령어를 사용한 클래스로 TypeQuery 를 사용할 수 있어서 객체 변환 작업을 줄일 수 있다.
(new 다음에 변환받을 클래스의 패키지 명을 다 적어줘야 한다...)
+ 생성자 시그니쳐에 맞게 순서, 타입을 일치 시켜야 한다.
'spring > JPA' 카테고리의 다른 글
성능 최적화(1) - N+1 (0) | 2024.02.07 |
---|---|
JPQL(3) - 페이징, 조인 (1) | 2024.01.25 |
JPQL(1) - 기본 문법 (0) | 2024.01.24 |
JPA - 값 타입 (0) | 2024.01.20 |
JPA - 즉시 로딩과 지연 로딩, 영속성 전이, 고아 객체 (0) | 2024.01.19 |