Projections
엔티티 대신에 DTO를 편리하게 조회할 때 사용
전체 엔티티가 아니라 만약 회원 이름만 딱 조회하고 싶으면?
public interface UsernameOnly {
String getUsername();
}
조회할 엔티티의 필드를 getter 형식으로 지정하면 해당 필드만 선택해서 조회(Projection)
public interface MemberRepository ... {
List<UsernameOnly> findProjectionByUsername(@Param("username") String username);
}
메서드 이름은 자유, 반환 타입으로 인지
@Test
public void projection() {
Team teamA = new Team("teamA");
em.persist(teamA);
Member m1 = new Member(0, "m1", teamA);
Member m2 = new Member(0, "m2", teamA);
em.persist(m1);
em.persist(m2);
em.flush();
em.clear();
List<UsernameOnly> result = memberRepository.findProjectionByUsername("m1");
for (UsernameOnly usernameOnly : result) {
System.out.println("usernameOnly = " + usernameOnly);
}
}
select m.username from member m
where m.username=‘m1’;
SQL에서도 select절에서 username만 조회(Projection)하는 것을 확인
네이티브 쿼리
가급적 네이티브 쿼리는 사용하지 않는게 좋음, 정말 어쩔 수 없을 때 사용
최근에 나온 궁극의 방법 스프링 데이터 Projections 활용
스프링 데이터 JPA 기반 네이티브 쿼리
- 페이징 지원
- 반환 타입
- Object[]
- Tuple
- DTO(스프링 데이터 인터페이스 Projections 지원)
- 제약
- Sort 파라미터를 통한 정렬이 정상 동작하지 않을 수 있음(믿지 말고 직접 처리)
- JPQL처럼 애플리케이션 로딩 시점에 문법 확인 불가
- 동적 쿼리 불가
JPA 네이티브 SQL 지원
public interface MemberRepository extends JpaRepository<Member, Long> {
@Query(value = "select * from member where username = ?", nativeQuery = true)
Member findByNativeQuery(String username);
}
JPQL은 위치 기반 파리미터를 1부터 시작하지만 네이티브 SQL은 0부터 시작
네이티브 SQL을 엔티티가 아닌 DTO로 변환은 하려면
- DTO 대신 JPA TUPLE 조회
- DTO 대신 MAP 조회
- @SqlResultSetMapping -> 복잡
- Hibernate ResultTransformer를 사용해야함 -> 복잡
- 네이티브 SQL을 DTO로 조회할 때는 JdbcTemplate or myBatis 권장
Projections 활용
정적 쿼리를 네이티브로 짜야할때는 Projections 기능을 가지고 해결할 수 있다.
예) 스프링 데이터 JPA 네이티브 쿼리 + 인터페이스 기반 Projections 활용
@Query(value = "SELECT m.member_id as id, m.username, t.name as teamName " +
"FROM member m left join team t ON m.team_id = t.team_id",
countQuery = "SELECT count(*) from member",
nativeQuery = true)
Page<MemberProjection> findByNativeProjection(Pageable pageable);
동적 네이티브 쿼리
하이버네이트를 직접 활용
스프링 JdbcTemplate, myBatis, jooq같은 외부 라이브러리 사용
예) 하이버네이트 기능 사용
//given
String sql = "select m.username as username from member m";
List<MemberDto> result = em.createNativeQuery(sql)
.setFirstResult(0)
.setMaxResults(10)
.unwrap(NativeQuery.class)
.addScalar("username")
.setResultTransformer(Transformers.aliasToBean(MemberDto.class))
.getResultList();
}
'JPA > Spring Data Jpa' 카테고리의 다른 글
스프링 데이터 JPA 분석 (0) | 2024.08.27 |
---|---|
확장 기능 (0) | 2024.08.26 |
쿼리 메소드 기능 (0) | 2024.08.26 |
공통 인터페이스 기능 (0) | 2024.08.25 |