Рубрики
Без рубрики

Spring Data JPA-запрос на примере

Узнайте, как использовать запрос Spring Data на примере API

Автор оригинала: baeldung.

1. введение

В этом уроке мы собираемся узнать, как запрашивать данные с помощью Spring Data | Query by Example API .

Во-первых, мы определим схему данных, которые мы хотим запросить. Далее мы рассмотрим несколько соответствующих классов из данных Spring. А затем мы рассмотрим несколько примеров.

Давайте начнем!

2. Данные Испытаний

Наши тестовые данные-это список имен пассажиров, а также место, которое они занимали.

Кузнец Джилл 50
Джексон Канун 94
Блоги Фред 22
Бобби Рики 36
Колиси Сия 85

3. Домен

Давайте создадим хранилище данных Spring, в котором мы нуждаемся, и предоставим наш класс домена и тип идентификатора.

Для начала мы смоделировали наш 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 . Как мы видим, он расширяет интерфейс QueryByExample Executor для поддержки запроса на примере:

public interface JpaRepository
  extends PagingAndSortingRepository, QueryByExampleExecutor {}

Этот интерфейс представляет больше вариантов метода find () , с которыми мы знакомы по данным Spring. Однако каждый метод также принимает экземпляр 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 предоставляет методы для доступа к зонду , и Пример соответствует .

Важно понимать, что зонд является экземпляром нашей Сущности :

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());
    }
}

Таким образом, наш зонд и ваш Пример совпадений вместе определяют наш запрос.

5. Ограничения

Как и все остальное, запрос по примеру API имеет некоторые ограничения. Например:

  • Операторы вложенности и группировки не поддерживаются, например: ( Имя = ?0 и фамилия = ?1) или Номер места = ?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() строит Example , используя Example Matcher.matching() .

Другими словами, точное совпадение будет выполнено для всех ненулевых свойств | Пассажира . Таким образом, сопоставление чувствительно к регистру в свойствах String .

Однако было бы не слишком полезно, если бы все, что мы могли сделать,-это точное совпадение всех ненулевых свойств.

Именно здесь появляется Пример соответствия . Создав свой собственный Пример соответствия , мы можем настроить поведение в соответствии с вашими потребностями.

6.2. Сопоставление Без Учета Регистра

Имея это в виду, давайте рассмотрим другой пример, на этот раз используя с Ignore Case() для достижения соответствия без учета регистра:

@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. Пользовательское соответствие

Мы также можем настроить поведение наших совпадений на основе каждого свойства и сопоставить любое свойство с помощью Example Matcher.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. Игнорирование свойств

С другой стороны, мы также можем захотеть запросить только подмножество наших свойств .

Мы достигаем этого, игнорируя некоторые свойства с помощью Example Matcher.ignore Paths(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. Заключение

В этой статье мы продемонстрировали, как использовать запрос на примере API.

Мы продемонстрировали, как использовать Example и Example Matches вместе с интерфейсом QueryByExampleExecutor для запроса таблицы с использованием экземпляра данных примера.

В заключение, вы можете найти код на GitHub .