"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."
www.inflearn.com/course/ORM-JPA-Basic#
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그
www.inflearn.com
프로젝션
- SELECT 절에 조회할 대상을 지정하는 것으로 그 대상으로는 Entity, Embedded type, Scala type(숫자, 문자등 기본 데이터 타입) 이 있다.
1. Entity 프로젝션의 경우
- JpaMain.java
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();
Member findMember = result.get(0);
findMember.setAge(20);
코드를 위와 같이 작성해서 Entity 를 검색하여 List 컬렉션에 Entity 데이터들이 반환되는 경우, 해당 데이터들은 영속성 컨텍스트에서 관리를 해줄까?
애플리케이션을 실행해보면 아래와 같은 Hibernate SQL 을 출력하는 것을 볼 수 있다.
- Hibernate SQL
Hibernate:
/* select
m
from
Member m */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as team_id4_0_,
member0_.username as username3_0_
from
Member member0_
Hibernate:
/* update
jpql.Member */ update
Member
set
age=?,
TEAM_ID=?,
username=?
where
id=?
위의 Hibernate SQL 을 보면 update query 가 실행되고 있음을 볼 수 있다.
즉, Entity 프로젝션을 하면 검색된 Entity 대상이 몇개가 됐든 전부 다 영속성 컨텍스트에서 관리된다는 것을 알 수 있다.
아래와 같이 JPQL 을 작성해도 Entity 프로젝션 으로서 영속성 컨텍스트에 관리된다.
- JpaMain.java
// 테이블 inner 조인 Entity 프로젝션
List<Team> result = em.createQuery("select m.team from Member m", Team.class)
.getResultList();
또한 위의 코드를 실행하면 테이블 조인 쿼리가 나가게 된다.
(연관관계를 가지고 있는 서로 다른 도메인 테이블의 데이터를 가져오므로)
- Hibernate SQL
Hibernate:
/* select
m.team
from
Member m */ select
team1_.id as id1_3_,
team1_.name as name2_3_
from
Member member0_
inner join /* 테이블 inner 조인 */
Team team1_
on member0_.TEAM_ID=team1_.id
그런데 겉으로 보기에는 위와 같이 코드를 작성하면 좋아보이나, 테이블 조인 기능을 활용할 땐 웬만하면 SQL 과 비슷하게 작성해 주어야 한다.
테이블 조인 자체가 성능에 영향을 끼칠 가능성이 다분하다, 그렇기 때문에 한눈에 보이도록 코드를 작성해주는 것이다.
(쉽게 말해, 어느 타이밍에 테이블 조인이 발생하는지 쉽게 예측이 가능해진다.)
- JpaMain.java
List<Team> result = em.createQuery("select t from Member m join m.team t". Team.class)
.getResultList(); // 테이블 inner 조인을 직접 작성해준다.
- Hibernate SQL
Hibernate: /* 주석만 다르게 나왔다. */
/* select
t
from
Member m
join
m.team t */ select
team1_.id as id1_3_,
team1_.name as name2_3_
from
Member member0_
inner join
Team team1_
on member0_.TEAM_ID=team1_.id
2. Embedded type 프로젝션의 경우
- JpaMain.java
// Order 클래스에 선언되어 있는 임베디드 타입인 Address 클래스의 데이터를 가져온다.
List<Address> result_address = em.createQuery("select o.address from Order o", Address.class)
.getResultList();
- Hibernate SQL
Hibernate:
/* select
o.address
from
Order o */ select
order0_.city as col_0_0_,
order0_.street as col_0_1_,
order0_.zipcode as col_0_2_ from
ORDERS order0_
/* Order 클래스 내부에 선언된 Address 클래스의 데이터들만 select 해 오는 것을 확인할 수 있다. */
그런데 임베디드 타입은 한계가 있다.
예를 들어 JPQL 을 아래와 같이 작성할 수 없다.
- JpaMain.java
List<Address> result_address = em.createQuery("select address from Address o", Address.class)
.getResultList();
// 이와 같이 코드를 작성할 수 없다.(오류가 발생함)
왜? 임베디드 타입은 어딘가에 소속되어 있는 클래스 타입으로서, 소속되어 있는 도메인 클래스를 통해 데이터 들을 가져와야 하기 때문이다.
즉, 클래스 자체적으로 데이터를 찾아올 수 없다.
3. Scala 타입 프로젝션의 경우
- JpaMain.java
// 반환 타입이 명확하지 않기 때문에 TypedQuery 형태로 코드를 작성하면 안된다.
// 즉, JPQL 코드 이후 클래스 정보를 넘겨주면 안된다.
em.createQuery("select distinct m.username, m.age from Member m")
.getResultList(); // distince 로 중복을 제거하였다.
- Hibernate SQL
Hibernate:
/* select
distinct m.username,
m.age
from
Member m */ select /* distinct 로 중복을 제거하였다. */
distinct member0_.username as col_0_0_,
member0_.age as col_1_0_
from
Member member0_
스칼라 타입 프로젝션은 일반 SQL 의 select 프로젝션과 거의 똑같다고 보면 된다.
그런데 고민거리가 하나 생길 수 있다.
가져와야 하는 타입이 명확하지 않을 경우는 어떻게 데이터를 가져와야 할까?
즉, 위의 코드와 같이 가져와야 하는 데이터 타입이 2개 이상일 경우라면 어떻게 해야할까?
다음 글에서는 프로젝션에서 여러 값을 조회하는 방법을 알아보자.
'JPA' 카테고리의 다른 글
JPQL - JPQL 기본(4) (0) | 2020.11.16 |
---|---|
JPQL - JPQL 기본(3) (0) | 2020.11.16 |
JPQL - JPQL 기본(1) (0) | 2020.11.15 |
JPQL - JPQL 소개(2) (0) | 2020.11.13 |
JPQL - JPQL 소개(1) (0) | 2020.11.13 |