1. Въведение
В този урок ще научим как да заявяваме данни с Spring Data Query чрез пример API .
Първо ще дефинираме схемата на данните, които искаме да направим. След това ще разгледаме няколко от съответните класове от Spring Data. И тогава ще разгледаме няколко примера.
Да започваме!
2. Тестовите данни
Нашите тестови данни са списък с имената на пътниците, както и мястото, което са заели.
Първо име | Фамилия | Номер на седалката |
---|---|---|
Джил | Смит | 50 |
Ева | Джаксън | 94 |
Фред | Bloggs | 22. |
Рики | Боби | 36 |
Сия | Колиси | 85 |
3. Домейн
Нека създадем хранилището Spring Data, от което се нуждаем, и да предоставим нашия клас на домейн и тип id.
Като начало моделирахме нашия пътник като 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 {}
Този интерфейс представя повече варианти на метода find () , с които сме запознати от Spring Data. Всеки метод обаче приема и екземпляр от Пример :
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); }
На второ място, примерният интерфейс излага методи за достъп до сондата и ExampleMatcher .
Важно е да осъзнаете, че сондата е екземпляр на нашата Същност :
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
- Съвпадението на низове включва само точно, без регистър, начало, край, съдържание и регулярно изражение
- Всички видове, различни от String, са само с точно съвпадение
Сега, когато сме малко по-запознати с 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 () .
С други думи, ще бъде извършено точно съвпадение на всички ненулеви свойства на Пътника . По този начин, съвпадението е чувствително към регистъра на свойствата String .
Въпреки това, не би било твърде полезно, ако всичко, което можехме да направим, беше точно съвпадение на всички ненулеви свойства.
Това е мястото, където се появява 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.
Демонстрирахме как да използваме Example и ExampleMatcher заедно с интерфейса QueryByExampleExecutor за заявка на таблица, използвайки примерен екземпляр от данни.
В заключение можете да намерите кода на GitHub.