프로젝션(조회)
- SELECT 절에 조회할 대상을 지정하는 것
프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 기본데이터 타입 등)
엔티티 타입
예시)
엔티티 프로젝션
SELECT m FROM Member m;
SELECT m.team FROM Member m;
=> team으로 조회할 때 Member에서 Team으로 자동으로 join쿼리를 날려 조회하는 것이다. 이를 알고 명시해주는 작업이 초보자들에겐 필요할 수 있는데, 따라서
"SELECT t from Member m join m.team t"
로 조회하는 것 더 이해하고 학습하기 좋을 것 같다.
임베디드 타입
예시)
임베디드 프로젝션
SELECT m.address FROM Member m;
생성한 임베디드 타입 address로 그대로 조회해도 address내의 속성들로 자동 매핑되어 쿼리가 나가고, 조회된다.
스칼라 타입
예시)
스칼라 프로젝션(숫자, 문자 기본데이터 타입 등)
SELECT m.username, m.age FROM Member m;
distinct가 사용 가능하다.
보통
List<반환타입> resultList = em.createQuery("쿼리문", 반환 타입). getResultList();
위와 같은 코드로 조회를 했었는데, 스칼라 프로젝션은 반환타입이 뚜렷하지 않아서 조회하기 어려움을 겪을 수 있다. 반환타입이 뚜렷하지 않은 경우 조회할 수 있는 방법은 3가지가 있다.
조회방법 3가지
1. Query타입으로 조회
=> 불편해서 생략..
2. Object[] 타입으로 조회
데이터 삽입
Member member = new Member();
member.setAge(20);
Team team = new Team();
team.setName("호랑이팀");
member.setTeam(team);
member.setUsername("정석우");
em.persist(team);
em.persist(member);
em.flush();
em.clear();
스칼라 타입 조회
List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m").getResultList();
for (Object[] result : resultList) {
System.out.println("username = " + result[0]);
System.out.println("age = " + result[1]);
}
1. List의 타입에 Object[]로 설정하고, createQuery의 2번째 파라미터를 비워두어서 타입을 특정짓지 않는다.
2. Object[]에 순서대로 각 스칼라의 값들이 담겨 있다, iter로 추출하여 조회해보자.
=> 주의**: 만약 m.team 등 조인 된 다른 객체를 조회해서 String으로 출력할때, 해당 클래스의 toString() 메소드가 어떻게 구현되어 있느냐에 따라 무한루프가 돌 수 있다. 다른 클래스를 toString()으로 출력할 때는 꼭 무한루프가 도는지 안도는지 확인해서 조회 할 수 있도록 하자 !!
3. new 명령어로 조회
단순 값을 DTO로 바로 조회 가능함
-> DTO타입을 만들고, new 라는 키워드를 사용해야함
주의: 조회시 패키지명을 포함한 전체 클래스명 입력 필요 , 순서와 타입이 일치하는 생성자 필요
예시)
위의 예제와 똑같이 username과 age를 조회하려한다면, 이 속성들을 포함한 DTO를 생성하면 된다. 특히 주의할 점은 생성자를 조회할 속성 순서에 맞게 만들어놔야 한다.
MemberDTO class
package jpql;
public class MemberDTO {
private String username;
private int age;
public MemberDTO(String username, int age) {
this.username = username;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
DTO를 통해 스칼라 조회
List<MemberDTO> resultList = em.createQuery("select new jpql.MemberDTO(m.username, m.age) from Member m", MemberDTO.class).getResultList();
for(MemberDTO memberDTO : resultList){
System.out.println("username = " + memberDTO.getUsername());
System.out.println("age = " + memberDTO.getAge());
}
1. List타입과, createQuery의 타입을 MemberDTO라는 클래스로 지정할 수 있다.
2. "select new jpql.MemberDTO(m.username, m.age) from Member m"
** new라는 키워드를 꼭 사용해야하고 패키지명을 포함한 전체 경로 클래스 명으로 설정해야 한다. **
+JPQL의 프로젝션으로 조회한 모든 데이터들은 영속성 컨텍스트 안에서 관리된다.
페이징 API
JPA는 페이징을 다음 두 API로 추상화한다.
setFirstResult(int startPosition): 조회 시작 위치(0부터 시작)
setMaxResults(int maxResult): 조회할 데이터 수
예시)
for (int i = 0; i < 100; i++) {
Member member = new Member();
member.setAge(i);
member.setUsername("이름" + i);
em.persist(member);
}
em.flush();
em.clear();
List<Member> resultList = em.createQuery("select m from Member m order by m.age desc", Member.class)
.setFirstResult(0)
.setMaxResults(10)
.getResultList();
for (Member member : resultList) {
System.out.println("username = " + member.getUsername());
System.out.println("age = " + member.getAge());
}
조회 쿼리에서 order by m.age desc로 설정했으므로 age가 높은 순서대로 조회가 될 것이다.
setFirstResult는 0번째부터(첫번째 값)
setMaxResults는 10개로 설정했기 때문에
age가 99인 데이터부터 age가 90인 데이터까지 차례대로 10개가 출력될 것이다.
출력결과
날아간 쿼리
아래에 limit 키워드가 나간 것으로 보아 h2 DB에 맞게 쿼리가 날아간 모습이고
출력도 잘 된 모습이다.
이 게시물은 '자바 ORM 표준 JPA 프로그래밍' 강의를 수강하고 정리한 내용임을 밝힙니다.
출처: https://www.inflearn.com/course/ORM-JPA-Basic#
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 본 강의는 자바 백엔
www.inflearn.com