프로젝션
프로젝션이란 select 절에 조회할 대상을 쿼리를 통해서 지정하는 것을 의미한다. 만일 엔티티 Member에 name, age라는 필드가 존재하고 그 중 내가 name을 조회하고 싶다라면 조회할 대상으로 name을 지정하는 것을 의미한다.
jpql을 통해서 값 가져오기
예시) 연관 관계 엔티티 프로젝션
package jpql;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
public class JpqlMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Team team = new Team();
team.setName("TEAM1");
Member member = new Member();
member.setUsername("member1");
member.setAge(10);
member.changeTeam(team);
em.persist(member);
em.flush();
em.clear();
List<Team> resultList =
em.createQuery("select m.team from Member m", Team.class).getResultList();
/*List<Team> resultList =
em.createQuery("select t from Team t", Team.class).getResultList();*/
Team team1 = resultList.get(0);
System.out.println("team1 = " + team1.getName());
tx.commit();
} catch (Exception e) {
tx.rollback(); // 오류 발생 시 롤백
e.printStackTrace(); // 에러 내용 출력
} finally {
//종료
em.close();
}
emf.close();
}
}
Hibernate:
/* insert jpql.Team
*/ insert
into
Team
(name, id)
values
(?, ?)
Hibernate:
/* insert jpql.Member
*/ insert
into
Member
(age, TEAM_ID, username, id)
values
(?, ?, ?, ?)
Hibernate:
/* select
m.team
from
Member m */ select
team1_.id as id1_3_,
team1_.name as name2_3_
from
Member member0_
inner join
Team team1_
on member0_.TEAM_ID=team1_.id
team1 = TEAM1
여러 값 조회
Object로 조회하는 경우
예시) 스칼라 타입 프로젝션
package jpql;
import javax.persistence.*;
import java.util.List;
public class JpqlMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);
em.flush();
em.clear();
// 여러 개의 스칼라 타입 프로젝션(username, age)
List resultList = em.createQuery("select m.username, m.age from Member m")
.getResultList();
Object o = resultList.get(0);
// 배열형으로 형 변환
Object[] results = (Object[]) o;
// o 자체는 Object 형 객체
System.out.println("o = " + o);
System.out.println("results(username) = " + results[0]);
System.out.println("results(age) = " + results[1]);
tx.commit();
} catch (Exception e) {
tx.rollback(); // 오류 발생 시 롤백
e.printStackTrace(); // 에러 내용 출력
} finally {
//종료
em.close();
}
emf.close();
}
}
Hibernate:
/* insert jpql.Member
*/ insert
into
Member
(age, TEAM_ID, username, id)
values
(?, ?, ?, ?)
Hibernate:
/* select
m.username,
m.age
from
Member m */ select
member0_.username as col_0_0_,
member0_.age as col_1_0_
from
Member member0_
o = [Ljava.lang.Object;@67f77f6e
result(username) = member1
result(age) = 10
Object[ ] 로 조회하는 경우
참고로 위에서 프로젝션을 할때, m.username, m.age처럼 여러개의 타입을 동시에 조회하는 경우
단순 Object형 (위 코드에서는 Object o)으로 값을 받아서 이를 Object[ ]으로 배열로 형 변환을 해주어야 했다.
- List resultList = em.createQuery(" ").getResultList( ); // 조회할 타입을 명시하지 않았으므로 단순 List로 조회
- Object o = resultList.get(index); // 리스트에서 인덱스로 특정 스칼라 타입들의 모음([username,age])을 get 함.
- Object[ ] results = (Object[ ]) o; // 단순 Object 객체에서 배열로 형 변환
- results[0] <- username / result[1] <- age
근데 여기서 배열로 형 변환 이 과정이 매우 귀찮다. 그래서 다음과 아예 em.createQuery().getResultList(); 할 때 반환 타입을 List<Object[ ]>로 받는다.
비교
1) 쿼리 결과를 기존 처럼 List로 받는 경우
// 반환형이 List인 경우
List resultList = em.createQuery("select m.username, m.age from Member m")
.getResultList();
// Object 객체로 get()
Object o = resultList.get(0);
// 배열형으로 형 변환
Object[] results = (Object[]) o;
// 출력
System.out.println("results(username) = " + results[0]);
System.out.println("results(age) = " + results[1]);
2) 쿼리 결과를 List<Object[ ]> 배열로 받는 경우
// 반환형을 List가 아닌 List<Object[]>로 함
List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m").getResultList();
// 한번에 배열로 get()
Object[] results = resultList.get(0);
// 출력
System.out.println("results(username) = " + results[0]);
System.out.println("results(age) = " + results[1]);
new 명령어로 조회
new를 통해서 객체로 값을 받아서 객체의 getter를 통해서 조회하는 방법도 있다.
MemberDTO.class
package jpql;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class MemberDTO {
private String username;
private int age;
}
JpqlMain.class
package jpql;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
public class JpqlMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);
em.flush();
em.clear();
// 객체를 통한 조회=> select new 조회 시에 패키지명.조회필드를 담은 클래스 from 엔티티
List<MemberDTO> resultList =
em.createQuery("select new jpql.MemberDTO(m.username, m.age) from Member m", MemberDTO.class)
.getResultList();
// 조회된 값이 담긴 DTO 객체
MemberDTO memberDTO = resultList.get(0);
// 객체에서 getter로 값 꺼내기
int age = memberDTO.getAge();
String username = memberDTO.getUsername();
tx.commit();
} catch (Exception e) {
tx.rollback(); // 오류 발생 시 롤백
e.printStackTrace(); // 에러 내용 출력
} finally {
//종료
em.close();
}
emf.close();
}
}
근데 이거 쓰려면 쿼리 문에 패키지명을 포함한 전체 클래스명을 입력해줘야함. 그리고 조회하고자 하는 값들의 순서에 맞는 생성자가 필요함.
'Spring > JPA' 카테고리의 다른 글
JPA- 조인 (0) | 2023.05.14 |
---|---|
JPA- 페이징 (0) | 2023.05.13 |
JPA- 기본 문법과 쿼리 API (0) | 2023.05.07 |
JPA- 값 타입 컬렉션 (0) | 2023.04.30 |
JPA- 값 타입의 비교 (0) | 2023.04.30 |