- Specifications
- Query By Example
- Projections
- 네이티브 쿼리
Specifications을 지원하는데 JPA Criteria를 활용해서 개념을 사용할 수 있도록 지원해준다.
=> 실무에서 잘 사용하지 않는다.
술어(predicate)
- 참 또는 거짓으로 평가
- AND OR 같은 연산자로 조합해서 다양한 검색조건을 쉽게 생성(디자인 패턴을 컴포지트 패턴으로 생성)
- 예) 검색 조건 하나하나
- 스프링 데이터 JPA는 `org.springframework.data.jap.domain.Specification` 클래스로 정의
사용방법을 보고 간단하게 넘어가자.
// MemberRepository Interface
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom, JpaSpecificationExecutor<Member> {
List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
아래와 같이 테스트 케이스를 작성해주고
@Test
public void specBasic() {
// given
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
memberRepository.findAll();
}
MemberSpec을 만든 후에
아래와 같이 코드 작성
// MemberSpec
package study.datajpa.repository;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import study.datajpa.entity.Member;
import study.datajpa.entity.Team;
import javax.persistence.criteria.*;
public class MemberSpec {
// teamName 검색조건으로 넣을 것이다.
public static Specification<Member> teamName(final String teamName) {
return (root, query, builder) -> {
if (StringUtils.isEmpty(teamName)) {
return null;
}
// JPA Criteria 문법 => JPQL 만듬
Join<Member, Team> t = root.join("team", JoinType.INNER);// 회원과 조인
return builder.equal(t.get("name"), teamName);
};
}
public static Specification<Member> username(final String username) {
return (Specification<Member>) (root, query, builder) ->
builder.equal(root.get("username"), username);
}
}
테스트 코드에 when절을 작성후에 실행시키면
@Test
public void specBasic() {
// given
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
Specification<Member> spec = MemberSpec.username("m1").and(MemberSpec.teamName("teamA"));
List<Member> result = memberRepository.findAll(spec);
Assertions.assertThat(result.size()).isEqualTo(1);
}
쿼리 나가는 걸 보면 아래와 같다.
select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.created_date as created_3_1_,
member0_.tema_id as tema_id5_1_,
member0_.username as username4_1_
from
member member0_
inner join
team team1_
on member0_.tema_id=team1_.team_id
where
member0_.username=?
and team1_.name=?
2022-04-19 15:50:34.661 INFO 71773 --- [ main] p6spy : #1650351034661 | took 0ms | statement | connection 3| url jdbc:h2:tcp://localhost/~/datajpa
select member0_.member_id as member_i1_1_, member0_.age as age2_1_, member0_.created_date as created_3_1_, member0_.tema_id as tema_id5_1_, member0_.username as username4_1_ from member member0_ inner join team team1_ on member0_.tema_id=team1_.team_id where member0_.username=? and team1_.name=?
select member0_.member_id as member_i1_1_, member0_.age as age2_1_, member0_.created_date as created_3_1_, member0_.tema_id as tema_id5_1_, member0_.username as username4_1_ from member member0_ inner join team team1_ on member0_.tema_id=team1_.team_id where member0_.username='m1' and team1_.name='teamA';
- 실무에서는 JPA Criteria를 거의 안쓴다! QueryDSL을 사용하자.
<출처 김영한: 실전! 스프링 데이터 JPA >
'Spring > SpringDataJPA' 카테고리의 다른 글
Projections (0) | 2022.04.19 |
---|---|
Query By Example (0) | 2022.04.19 |
새로운 엔티티를 구별하는 방법 (0) | 2022.04.18 |
스프링 데이터 JPA 구현체 분석 (0) | 2022.04.18 |
Web 확장 - 도메인 클래스 컨버터 & 페이징과 정렬 (0) | 2022.04.18 |