1. 소개
이 튜토리얼에서는 Spring Data Query by Example API를 사용하여 데이터를 쿼리하는 방법을 배웁니다 .
먼저 쿼리 할 데이터의 스키마를 정의합니다. 다음으로 SpringData의 관련 클래스 몇 가지를 살펴 보겠습니다. 그런 다음 몇 가지 예를 살펴 보겠습니다.
시작하자!
2. 테스트 데이터
테스트 데이터는 승객 이름과 그들이 차지한 좌석 목록입니다.
이름 | 성 | 좌석 번호 |
---|---|---|
처녀 | 스미스 | 50 |
이브 | 잭슨 | 94 |
프레드 | 블로그 | 22 |
리키 | 바비 | 36 |
시야 | Kolisi | 85 |
3. 도메인
우리가 필요로하는 Spring Data Repository를 생성하고 도메인 클래스와 id 유형을 제공합시다.
먼저 Passenger 를 JPA 엔티티로 모델링했습니다 .
@Entity class Passenger { @Id @GeneratedValue @Column(nullable = false) private Long id; @Basic(optional = false) @Column(nullable = false) private String firstName; @Basic(optional = false) @Column(nullable = false) private String lastName; @Basic(optional = false) @Column(nullable = false) private int seatNumber; // constructor, getters etc. }
JPA를 사용하는 대신 다른 추상화로 모델링 할 수 있습니다.
4. 예제 API로 쿼리
먼저 JpaRepository 인터페이스를 살펴 보겠습니다 . 보시다시피 QueryByExampleExecutor 인터페이스를 확장하여 예제 별 쿼리를 지원합니다.
public interface JpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor {}
이 인터페이스는 SpringData에서 익숙한 find () 메서드 의 더 많은 변형을 소개 합니다. 그러나 각 메서드는 Example 의 인스턴스도 허용합니다 .
public interface QueryByExampleExecutor { Optional findOne(Example var1); Iterable findAll(Example var1); Iterable findAll(Example var1, Sort var2); Page findAll(Example var1, Pageable var2); long count(Example var1); boolean exists(Example var1); }
둘째, Example 인터페이스는 프로브 및 ExampleMatcher 에 액세스하는 메서드를 노출합니다 .
프로브 가 Entity 의 인스턴스 임을 인식하는 것이 중요합니다 .
public interface Example { static org.springframework.data.domain.Example of(T probe) { return new TypedExample(probe, ExampleMatcher.matching()); } static org.springframework.data.domain.Example of(T probe, ExampleMatcher matcher) { return new TypedExample(probe, matcher); } T getProbe(); ExampleMatcher getMatcher(); default Class getProbeType() { return ProxyUtils.getUserClass(this.getProbe().getClass()); } }
요약하면 프로브 와 ExampleMatcher가 함께 쿼리를 지정합니다.
5. 제한
모든 것과 마찬가지로 Query by Example API에는 몇 가지 제한 사항이 있습니다. 예를 들면 :
- 중첩 및 그룹화 문은 지원되지 않습니다. 예 : ( firstName =? 0 및 lastName =? 1) 또는 seatNumber =? 2
- 문자열 일치에는 정확한 대소 문자 구분, 시작, 종료, 포함 및 정규식 만 포함됩니다.
- 문자열 이외의 모든 유형 은 정확히 일치 만 가능합니다.
이제 API와 그 제한 사항에 대해 조금 더 익숙해 졌으므로 몇 가지 예를 살펴 보겠습니다.
6. 예
6.1. 대소 문자 구분 일치
간단한 예제로 시작하여 기본 동작에 대해 이야기하겠습니다.
@Test public void givenPassengers_whenFindByExample_thenExpectedReturned() { Example example = Example.of(Passenger.from("Fred", "Bloggs", null)); Optional actual = repository.findOne(example); assertTrue(actual.isPresent()); assertEquals(Passenger.from("Fred", "Bloggs", 22), actual.get()); }
특히 정적 Example.of () 메서드는 ExampleMatcher.matching ()을 사용하여 Example 을 빌드합니다 .
즉, 정확히 일치하는 모든 null이 아닌 속성에 수행됩니다 의 여객 . 따라서 일치는 String 속성 에서 대소 문자를 구분 합니다.
그러나 우리가 할 수있는 모든 것이 null이 아닌 모든 속성에 대해 정확히 일치하는 것이라면 그다지 유용하지 않을 것입니다.
이것이 ExampleMatcher 가 들어오는 곳 입니다. 우리 자신의 ExampleMatcher 를 구축함으로써 우리는 우리의 필요에 맞게 동작을 사용자 정의 할 수 있습니다.
6.2. 대소 문자를 구분하지 않는 일치
이를 염두에두고 이번에는 withIgnoreCase () 를 사용하여 대소 문자를 구분하지 않는 일치를 달성 하는 또 다른 예를 살펴 보겠습니다 .
@Test public void givenPassengers_whenFindByExampleCaseInsensitiveMatcher_thenExpectedReturned() { ExampleMatcher caseInsensitiveExampleMatcher = ExampleMatcher.matchingAll().withIgnoreCase(); Example example = Example.of(Passenger.from("fred", "bloggs", null), caseInsensitiveExampleMatcher); Optional actual = repository.findOne(example); assertTrue(actual.isPresent()); assertEquals(Passenger.from("Fred", "Bloggs", 22), actual.get()); }
이 예제에서는 먼저 ExampleMatcher.matchingAll ()을 호출 했습니다 . 이전 예제에서 사용한 ExampleMatcher.matching () 과 동일한 동작을 합니다.
6.3. 맞춤 매칭
속성별로 매처의 동작을 조정하고 ExampleMatcher.matchingAny ()를 사용하여 모든 속성을 일치 시킬 수도 있습니다 .
@Test public void givenPassengers_whenFindByExampleCustomMatcher_thenExpectedReturned() { Passenger jill = Passenger.from("Jill", "Smith", 50); Passenger eve = Passenger.from("Eve", "Jackson", 95); Passenger fred = Passenger.from("Fred", "Bloggs", 22); Passenger siya = Passenger.from("Siya", "Kolisi", 85); Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); ExampleMatcher customExampleMatcher = ExampleMatcher.matchingAny() .withMatcher("firstName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()) .withMatcher("lastName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()); Example example = Example.of(Passenger.from("e", "s", null), customExampleMatcher); List passengers = repository.findAll(example); assertThat(passengers, contains(jill, eve, fred, siya)); assertThat(passengers, not(contains(ricki))); }
6.4. 속성 무시
반면에 속성의 하위 집합에 대해서만 쿼리 할 수도 있습니다 .
ExampleMatcher.ignorePaths (String… paths)를 사용하여 일부 속성을 무시하면됩니다 .
@Test public void givenPassengers_whenFindByIgnoringMatcher_thenExpectedReturned() { Passenger jill = Passenger.from("Jill", "Smith", 50); Passenger eve = Passenger.from("Eve", "Jackson", 95); Passenger fred = Passenger.from("Fred", "Bloggs", 22); Passenger siya = Passenger.from("Siya", "Kolisi", 85); Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); ExampleMatcher ignoringExampleMatcher = ExampleMatcher.matchingAny() .withMatcher("lastName", ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase()) .withIgnorePaths("firstName", "seatNumber"); Example example = Example.of(Passenger.from(null, "b", null), ignoringExampleMatcher); List passengers = repository.findAll(example); assertThat(passengers, contains(fred, ricki)); assertThat(passengers, not(contains(jill)); assertThat(passengers, not(contains(eve)); assertThat(passengers, not(contains(siya)); }
7. 결론
이 기사에서는 Query by Example API를 사용하는 방법을 설명했습니다.
예제 데이터 인스턴스를 사용하여 테이블을 쿼리하기 위해 QueryByExampleExecutor 인터페이스 와 함께 Example 및 ExampleMatcher 를 사용하는 방법을 시연했습니다 .
결론적으로 GitHub에서 코드를 찾을 수 있습니다.