Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 스프링 핵심 기능
- 스프링
- Servlet
- Greedy
- spring
- http
- Spring Boot
- pointcut
- springdatajpa
- SpringBoot
- AOP
- java
- 자바
- QueryDSL
- jpa
- 그리디
- Proxy
- db
- 스프링 핵심 원리
- kotlin
- 백준
- transaction
- 인프런
- 알고리즘
- Android
- 김영한
- Thymeleaf
- JDBC
- JPQL
- Exception
Archives
- Today
- Total
개발자되기 프로젝트
Projections 본문
- 엔티티 대신에 DTO를 편리하게 조회할 때 사용
- 전체 엔티티가 아니라 딱 회원의 이름만 조회하고 싶은 경우!
1. closed Projection
- 인터페이스만 생성하면 구현체는 SpringDataJpa가 만듦.
public interface UserNameOnly {
String getUserName();
}
- 사용 방법 : 아래와 같이 return type으로 인터페이스를 지정해주면 됨.
@Test
public void projections(){
Team teamA = new Team("teamA");
em.persist(teamA);
Member m1 = new Member("m1", 0, teamA);
Member m2 = new Member("m2", 0, teamA);
em.persist(m1);
em.persist(m2);
em.flush();
em.clear();
//when
List<UserNameOnly> result = memberRepository.findProjectionsByUserName("m1");
for (UserNameOnly userNameOnly : result) {
System.out.println("userNameOnly = " + userNameOnly);
}
}
- 반환 타입을 보면 스프링이 구현체를 만들어서 넣어준 것을 확인 가능.
select
member0_.user_name as col_0_0_
from
member member0_
where
member0_.user_name=?
2021-08-31 22:55:31.844 INFO 34388 --- [ main] p6spy : #1630418131844 | took 1ms | statement | connection 103| url jdbc:h2:tcp://localhost/~/datajpa
select member0_.user_name as col_0_0_ from member member0_ where member0_.user_name=?
select member0_.user_name as col_0_0_ from member member0_ where member0_.user_name='m1';
userNameOnly = org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap@258ac1e6
2. open Projection
- DB에서 엔티티 전체를 가져와서 애플리케이션에서 원하는 데이터만 찍을 수 있음
public interface UserNameOnly {
@Value("#{target.userName + ' ' + target.age}") //
String getUserName();
}
3. Class 기반 projection
@Getter
public class UserNameOnlyDto {
private String userName;
public UserNameOnlyDto(String userName) {
this.userName = userName;
}
}
- 파라미터 명(userName)을 가지고 분석함.
- 해당 파라미터를 가져와서 생성자를 통해 DTO반환
- Repository
List<UserNameOnlyDto> findProjectionsByUserName(@Param("userName") String userName);
- Test
List<UserNameOnlyDto> result = memberRepository.findProjectionsByUserName("m1");
for (UserNameOnlyDto userNameOnly : result) {
System.out.println("userNameOnly = " + userNameOnly);
}
4. 동적 projection
- Generic으로 넘기면 됨.
- Repository
<T> List<T> findProjectionsByUsername(String username, Class<T> type);
5. 중첩 구조
- 멤버랑 연관된 팀 까지 가져오기
public interface NestedClosedProjections {
String getUserName(); //root --> 최적화 해서 가져옴
TeamInfo getTeam(); //최적화 안하고 다가져옴
interface TeamInfo{
String getName();
}
}
- Repository
List<NestedClosedProjections> findProjectionsByUserName(@Param("userName") String userName);
- Test
//when
List<NestedClosedProjections> result = memberRepository.findProjectionsByUserName("m1");
for (NestedClosedProjections userNameOnly : result) {
System.out.println("userNameOnly = " + userNameOnly);
}
- root인 user는 최적화해서 UserName만 가져옴.
- team은 outer join으로 가져옴
select
member0_.user_name as col_0_0_,
team1_.team_id as col_1_0_,
team1_.team_id as team_id1_2_,
team1_.name as name2_2_
from
member member0_
left outer join
team team1_
on member0_.team_id=team1_.team_id
where
member0_.user_name=?
6. 정리
- 프로젝션 대상이 root 엔티티면, JPQL SELECT 절 최적화 가능
- 프로젝션 대상이 ROOT가 아니면
- LEFT OUTER JOIN 처리
- 모든 필드를 SELECT해서 엔티티로 조회한 다음에 계산
- 프로젝션 대상이 root 엔티티면 유용하다.
- 프로젝션 대상이 root 엔티티를 넘어가면 JPQL SELECT 최적화가 안된다!
- 실무의 복잡한 쿼리를 해결하기에는 한계가 있다.
- 실무에서는 단순할 때만 사용하고, 조금만 복잡해지면 QueryDSL을 사용하자
7. GitHub : 210831 Projection
'인프런 > [인프런] Spring Data JPA' 카테고리의 다른 글
Native Query (0) | 2021.09.01 |
---|---|
Query By Example (0) | 2021.08.31 |
SpringDataJpa의 구현체 (0) | 2021.08.31 |
Web 확장 : 도메인 클래스 컨버터, 페이징 & 정렬 (0) | 2021.08.31 |
Auditing (0) | 2021.08.30 |
Comments