나머지 기능들은 실제로 사용하기에는 애매한 부분들이 많다. 하여 이러한 기능들이 있다~ 정도로만 편하게 이해해보자.
Specifications
스프링 데이터 JPA는 JPA Criteria를 활용하여 Specifications라는 개념을 사용할 수 있도록 지원.(그런데 JPA Criteria를 사용한다는 것은 설계가 잘못된 어플리케이션일 수 있음. 되도록 사용하지 않도록 하자.)
Specification을 사용하기 위해서는 아래와 같이 이를 사용할 리퍼티토리에서 JpaSpecification<엔티티타입>을 extends 해주면 된다.
데이터 JPA Member리퍼지토리에서 이를 extends해보자.
//여기
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom, JpaSpecificationExecutor<Member>{
...
}
그리고 MemberSpec을 만들어준다.
public class MemberSpec {
//teamName으로 찾기
public static Specification<Member> teamName(final String teamName){
return (root, query, builder) -> {
if(StringUtils.isEmpty(teamName)) return null;
Join<Member, Team> t = root.join("team", JoinType.INNER);// 회원과 조인
return builder.equal(t.get("name"), teamName);
};
}
//username으로 찾기
public static Specification<Member> username(final String username) {
return (root, query, builder) -> builder.equal(root.get("username"), username);
}
}
이를 사용해보자.
@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--
//username == m1 이고, teamName == teamA 인 Member
Specification<Member> spec = MemberSpec.username("m1").and(MemberSpec.teamName("teamA"));
List<Member> result = memberRepository.findAll(spec);
//--then--
assertThat(result.size()).isEqualTo(1);
}
위의 테스트는 통과한다.
MemberSpec을 보면 보기에 매우 직관적이지 않다. teamName메서드를 보면 단순히 teamNamer과 조인하기 위해 이해하기 힘든 복잡한 코드를 사용해야 한다.
Query By Example
바로 테스트 코드를 보자.
@Test
void queryBuExample() {
//--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--
//Probe
Member member = new Member("m1"); //엔티티 자체가 검색조건이 된다.
ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("age");//age는 무시
Example<Member> example = Example.of(member,matcher);//member와 matcher로 example 생성
List<Member> result = memberRepository.findAll(example);
//--then--
assertThat(result.get(0).getUsername()).isEqualTo(m1.getUsername());
}
query by example을 사용하면 엔티티 자체가 검색조건이 된다.
• Probe: 필드에 데이터가 있는 실제 도메인 객체
• ExampleMatcher: 특정 필드를 일치시키는 상세한 정보 제공, 재사용 가능
• Example: Probe와 ExampleMatcher로 구성, 쿼리를 생성하는데 사용
장점
1. 동적 쿼리를 편리하게 처리
2. 도메인 객체를 그대로 사용
3. 데이터 저장소를 RDB에서 NOSQL로 변경해도 코드 변경이 없게 추상화 되어 있음 스프링 데이터 JPA JpaRepository 인터페이스에 이미 포함
단점
1. 조인은 가능하지만 내부 조인(INNER JOIN)만 가능함 외부 조인(LEFT JOIN) 안됨
2. 다음과 같은 중첩 제약조건 안됨
firstname = ?0 or (firstname = ?1 and lastname = ?2)
3. 매칭 조건이 매우 단순함
-문자는 starts/contains/ends/regex
-다른 속성은 정확한 매칭( = )만 지원
정리
실무에서 사용하기에는 매칭 조건이 너무 단순하고, LEFT 조인이 안됨 실무에서는 QueryDSL을 사용하자
김영한님의 인프런 강의와 PDF를 바탕으로 정리하였습니다.
'JPA > 스프링 DATA JPA' 카테고리의 다른 글
Data JPA 15 - Projections, 네이티브 쿼리 (0) | 2022.01.12 |
---|---|
Data JPA 13 - 스프링 데이터 JPA 분석 (0) | 2022.01.11 |
Data JPA 12 Web확장 : 도메인 클래스 컨버터, 페이징과 정렬 (0) | 2022.01.09 |
Data JPA 11 Auditing (0) | 2022.01.08 |
Data JPA 10 사용자 정의 리포지토리 구현 (0) | 2022.01.08 |