JPQL 을 쓸 때, 검색하는 방법을 알아보자.
JPQL 은 객체지향적 쿼리기 때문에, 에플리케이션상의 무언가와 매칭되어야 한다.
그 무언가의 종류에는 다음과 같은 종류가 있을 수 있다.
- 엔티티 타입
- 임베디드 타입
- 스칼라 타입
이번 글에서는 다음 엔티티를 사용한다.
@Entity
@Getter
@Setter
public class JPQLMember {
@Id
@GeneratedValue
private Long id;
private String username;
private int age;
@ManyToOne
@JoinColumn(name = "JPQLTEAM_ID")
private JPQLTeam team;
}
@Entity
@Getter
public class JPQLOrder {
@Id
@GeneratedValue
private Long id;
private int orderAmount;
@Embedded
private JPQLAddress address;
}
Entity Selection
select 문을 작성해보자.
Member 를 검색하는 JPQL 이다.
TypedQuery<JPQLMember> query = em.createQuery("select m from JPQLMember as m", JPQLMember.class);
List<JPQLTeam> resultList = query1.getResultList();
Member의 팀을 검색하는 JPQL 이다.
TypedQuery<JPQLTeam> query1 = em.createQuery("select m.team from JPQLMember as m", JPQLTeam.class);
List<JPQLTeam> resultList = query1.getResultList();
연관관계 맵핑된 컬럼의 조회같은 경우 아래와 같이 join 을 사용해서 가져온다.
쿼리문과 실제 날라가는 쿼리가 1:1 매칭되어야 보기 쉽기 때문에 위 방식보다는 join 문을 사용하는 것이 좋다.
/* select
m.team
from
JPQLMember as m */ select
jpqlteam1_.id as id1_14_,
jpqlteam1_.name as name2_14_
from
JPQLMember jpqlmember0_
inner join
JPQLTeam jpqlteam1_
on jpqlmember0_.JPQLTEAM_ID=jpqlteam1_.id
그리고, getResultList() 의 결과인 List 는 모두 엔티티메니저에 관리되어 영속성 컨텍스트를 가진다.
Embedded Selection
JPQLOrder 의 Address 임베디드 타입을 불러올 때에는 select 절에 임베디드 타입을 써주면 된다.
TypedQuery<JPQLAddress> query2 = em.createQuery("select o.address from JPQLOrder as o", JPQLAddress.class);
List<JPQLAddress> resultList2 = query2.getResultList();
/* select
o.address
from
JPQLOrder as o */ select
jpqlorder0_.city as col_0_0_,
jpqlorder0_.street as col_0_1_,
jpqlorder0_.zipcode as col_0_2_
from
JPQLOrder jpqlorder0_
Scala Selection
일반적으로 DB 에서 컬럼을 지정해서 가져오는 것을 생각하면 쉽다.
하지만 JPA 를 사용하기 때문에, 만약 Member 테이블의 age 와 name 을 가져온다 생각하면 리턴타입은 int 인가, String 인가 ?
이를 해결하기 위한 방법들은 아래와 같다.
1. raw 타입 List로 받아와서 명시적 형변환
List resultList3 = em.createQuery("select m.id, m.age from JPQLMember as m").getResultList();
Object o = resultList3.get(0);
Object[] o1 = (Object[]) o;
System.out.println("id : " + o1[0]);
System.out.println("age : " + o1[1]);
List 안에 배열 형태로 결과를 받아오기 때문에, get() 과 배열의 인덱스를 이용하여 값을 꺼내는 방법.
2. Object[] 타입 List로 받아오기
위의 방법보다 조금 낫지만 여튼 똑같은 방법이다.
List<Object[]> resultList4 = em.createQuery("select m.id, m.age from JPQLMember as m").getResultList();
Object[] o2 = resultList4.get(0);
System.out.println("id : " + o2[0]);
System.out.println("age : " + o2[1]);
3. new 명령어 사용
new 명령어로 DTO로 값을 매핑해서 받는다.
일단 결과를 받을 DTO 를 만든다.
package jpql;
public class MemberResultDto {
private Long id;
private String username;
public MemberResultDto(Long id, String username) {
this.id = id;
this.username = username;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
이후 JPQL 은 다음과 같이 작성한다.
List<MemberResultDto> resultList5 = em.createQuery("select new jpql.MemberResultDto(m.id, m.username) from JPQLMember as m", MemberResultDto.class).getResultList();
System.out.println("id : " + resultList5.get(0).getId());
System.out.println("age : " + resultList5.get(0).getUsername());
보다시피, Select 문에 new 키워드를 사용하여 생성자를 생성하듯이 해주면 자동으로 DTO 의 리스트를 반환한다.
createQuery() 의 두번째 인자로 DTO 클래스 타입을 준 것도 확인하자.
DTO 의 풀 패키지명(FQCL) 을 적어 준 것도 확인하자.
또, DTO 에는 해당 생성자가 필요하다.
결과적으로 다음과 같은 쿼리가 날라가게 된다.
/* select
new jpql.MemberResultDto(m.id,
m.username)
from
JPQLMember as m */ select
jpqlmember0_.id as col_0_0_,
jpqlmember0_.username as col_1_0_
from
JPQLMember jpqlmember0_
'JPA' 카테고리의 다른 글
JPQL (0) | 2021.04.22 |
---|---|
영속성 컨텍스트를 쓰면 좋은점 (0) | 2021.04.14 |
Entity Manager, 영속성 컨텍스트 (0) | 2021.04.13 |