JPA/JPA 기본

39. 프로젝션(select)

sdafdq 2023. 10. 30. 11:58

select 절에 조회할 대상을 지정하는 것.

 

그 뭐 sql에서 select 할 때 * 해서 모두 가져오기도 하고, select name, age 해서 뭐 이렇게 2개 가져오기도 하고 그거 말하는 거임.

 

일단 종류는

엔티티

임베디드 타입

스칼라타입(숫자, 문자 등 기본 데이터)

 

엔티티는 엔티티 자체, *랑 비슷할 거 같고,

임베디드 타입은 우리가 임베디드 정의한 거 사실 상 테이블에서는 그냥 열 몇개를 객체상에서는 모아놓은 거 이므로,

그냥 테이블에서 그 열들 조회해오는데 자바에서는 그게 그 임베디드 타입 객체로 얻어올 수 있단 이야기같고, 

스칼라타입 기본 타입은 그냥 가져오면 됨. name, age 등 숫자나 문자 기본 타입

 

환경에서 보자면

m -> 엔티티

m,team -> 엔티티

m.address -> 임베디드

m.username, m.age -> 스칼라 타입

 

참고로 sql과 마찬가지로 앞에 distinct 있으면 중복제거 가능.

 

 

 

참고로, JPQL은 다 영속성 컨텍스트에서 관리가 됨.

Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);

em.flush();
em.clear();

List<Member> result = em.createQuery("select m from Member m", Member.class)
                .getResultList();

result.get(0).setAge(30);

tx.commit();

여기 보면 애초에 쿼리를 내보내더라도 em을 써서 내보내기도 하고,

JPA에 의해 관리가 됨.

 

 

그리고 join

List<Team> result = em.createQuery("select m.team from Member m", Team.class)
                .getResultList();

이렇게 하면 member 테이블에서부터 join해서 가져옴.

Hibernate: 
    /* select
        m.team 
    from
        Member m */ select
            t1_0.id,
            t1_0.name 
        from
            Member m1_0 
        join
            Team t1_0 
                on t1_0.id=m1_0.team_id

근데 이거, join되는 거 명시를 해 주셈.

 

List<Team> result = em.createQuery("select t from Member m join m.team t", Team.class)
                .getResultList();

Member로부터 join해온다 Member의 team을 그 team의 별칭을 t 라고 하고 그 t라는 엔티티 프로젝션을 가져온다.

 

이렇게. 예측할 수 있게.

join 들어가고, 이렇게 sql 나가겠구나 할 수 있게.

 

 

그 다음 임베디드 타입

List<Address> result = em.createQuery("select o.address from Order o", Address.class)
                .getResultList();

이렇게 할 수 있다.

from에 들어갈 수 있는 건 아무리 그래도 엔티티 밖에 없다.

 

 

 

List resultList = em.createQuery("select m.username, m.age from Member m")
                            .getResultList();

스칼라 타입.

 

그럼 이럴 경우 값을 어떻게 돌려주냐?

for (Object o : resultList) {
    Object[] result = (Object[]) o;
    System.out.println("result = " + result[0]);
    System.out.println("result = " + result[1]);
}

좀 불편하긴 한데,

List<Object[]>

각각이 오브젝트 배열로 들어가 있는 느낌.

 

명시적 형변환도 해줘야 함.

 

아니면 그냥

List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m", Object[].class)
                            .getResultList();

        for (Object[] o : resultList) {
            System.out.println("result = " + o[0]);
            System.out.println("result = " + o[1]);
        }

 

애초에 받아올 때 각각을 오브젝트 배열로 받아오면 형변환은 생략 가능.

 

 

또 다른 방법은, 깔끔한 방법이기는 한데

List<MemberDTO> resultList = em.createQuery("select new hellojpa.MemberDTO(m.username, m.age) from Member m", MemberDTO.class)
                .getResultList();

for (MemberDTO dto : resultList) {
    System.out.println("result = " + dto.getUsername());
    System.out.println("result = " + dto.getAge());
}

이렇게 DTO를 만들어 new 패키지이름.생성자()

 

 

package hellojpa;
public class MemberDTO {
    private String username;
    private int age;

    public MemberDTO(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

이렇게 한다.

 

저건 특이하게 패키지.생성자() 이렇게 해야 한다.

select new 패키지.생성자(가져올값1, 가져올값2) from 엔티티

말 그대로 new, 새롭게 가져오는 것이다.

 

많이 씀.

 

좀 불편한 건 패키지 명을 포함한 전체 클래스명을 입력해야 하지만(문자이기에 한계) 그래도 괜찮음.

 

 

 

'JPA > JPA 기본' 카테고리의 다른 글

41. 조인  (0) 2023.10.31
40. 페이징  (0) 2023.10.31
38. JPQL 기본 문법  (0) 2023.10.30
37. JPQL  (0) 2023.10.30
36. 값타입 실전  (0) 2023.10.30