사실 이 기능들을 실무에서 잘 쓰지 않으니까 그냥 편하게 듣기
스프링 데이터 JPA는 JPA Criteria를 확용해 이 개념을 사용할 수 있도록 지원함
이 기능도 강사님은 실무에서 쓰지 못하도록 금지시키고 있음(하루만 지나도 읽을 수가 없음 ㅜ)
AND
OR
같은 연산자로 조합해 다양한 검색조건을 쉽게 생성함(컴포지트 패턴으로)org.springframework.data.jpa.domain.Specification
클래스로 정의명세 기능을 사용하려면 JpaSpecificationExecutor
인터페이스를 상속받으면 된다.
Specification
을 파라미터로 받아 검색 조건으로 사용한다.
Specification
을 구현하면 명세들을 조립할 수 있다.
(where()
, and()
, or()
, not()
제공)
findAll을 보면 (예제 상에서)회원 이름 명세(username)과 팀 이름 명세(teamName)를 and
로 조합해 검색 조건으로 사용한다.
명세를 정의하려면 Specification
인터페이스를 구현
명세를 정의할 때는 toPredicate(...)
메소드만 구현하면 되는데 JPA Criteria의 Root
, CriteriaQuery
, CriteriaBuilder
클래스를 파라미터 제공
(예제에서는 편의상 람다를 사용)
⚠️ 실무에서는 JPA Criteria를 거의 쓰지 않는다! 대신 QueryDSL을 사용한다!
이전과 같이 쿼리를 하는데 Example에 의해 쿼리를 하겠다(?)
(그 옆에 age가 함께 설정되는 것은 ExampleMatcher를 생성해 무시시키면 됨)
Probe
란 필드에 데이터가 있는 실제 도메인 객체ExampleMatcher
는 특정 필드를 일치시키는 상세한 정보를 제공하며 재사용이 가능Example
: Probe
와 ExampleMatcher
로 구성되었으며 쿼리를 생성하는데 사용JpaRepository
) 인터페이스에 이미 포함 (repository를 받으면 그냥 쓸 수 있음)⚠️ 강사님은 조인이 안되면 실무에 도입하지 않는 편
firstname = ?0 or (firstname = ?1 and lastname = ?2)
starts/contains/ends/regex
=
)만 지원 (equal 정도만 지원한다고 보면 됨)즉, 실무에서 사용하기엔 매칭 조건이 너무 단순하고 LEFT 조인이 안된다.
그냥 실무에서는 QueryDSL을 사용하자!
자꾸 똑같은 결론이 나는 강사님,,,
앞 기능들은 자꾸 도움이 안된다고 했는데 이건 그래도 좀 쓸모가 있어서 알아두면 좋음^^,,
엔티티 대신 DTO를 편리하게 조회할 때 사용한다.
예를 들어 전체 엔티티가 아니라 회원 이름만!! 조회하고 싶다면,, 🤷🏻♀️
회원 이름만 조회하고 싶다면 인터페이스에 getUsername()만 만들어놓으면 실제 구현체는 스프링 데이터 JPA가 만들어줌
조회할 엔티티의 필드를 getter 형식으로 지정하면 해당 필드만 선택해 조회(Projection)
➡️ 인터페이스에 추상화시킨 username만 정확하게 가져올 수 있게 되었음.
스프링 SpEL 문법 지원
⚠️ 단, SpEL 문법을 사용하면, DB에서 엔티티 필드를 다 조회해온 다음 계산한다. 따라서 JPQL SELECT 절 최적화가 안된다.
인터페이스가 아닌 구체적인 DTO 형식도 가능하다.
생성자의 파라미터 이름으로 매칭된다.
➡️ UsernameOnlyDto로 바꿔 돌린 결과
Generic type을 주면 동적으로 프로젝션 데이터를 변경할 수 있다.
📌 즉, 정리하자면
- 프로젝션 대상이 root 엔티티면 유용
- 프로젝션 대상이 root 엔티티를 넘어가면 JPQL SELECT 최적화가 안됨!!
- 실무의 복잡한 쿼리를 해결하기엔 한계
- 실무에서는 단순할 때만 사용, 조금만 복잡해지면 QueryDSL을 사용
어,,?
제약이 너무 많기 때문에 가급적 네이티브 쿼리는 사용하지 않는 것이 가장 좋다‼️ (정말 어쩔 수 없을 때만 사용하자,,)
최근에 나온 궁극의 방법 → 스프링 데이터 Projections 사용
JPQL은 위치 기반 파라미터를 1부터 시작하지만 네이티브 SQL은 0부터 시작
네이티브 SQL을 엔티티가 아닌 DTO로 변환하려면
@SqlResultSetMapping
→ 복잡