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

Весенние данные JPA и нулевые параметры

Изучите различные способы использования нулевых параметров с запросами Spring Data JPA, включая то, как сделать параметры запроса необязательными.

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

1. Обзор

В этой статье мы покажем способы обработки null параметров в Spring Data JPA .

В некоторых случаях, когда мы ищем записи по параметрам , мы хотим найти строки с null в качестве значения поля . В других случаях мы можем проигнорировать null и пропустить это поле в нашем запросе .

Ниже мы покажем, как реализовать каждый из них.

2. Быстрый Пример

Допустим, у нас есть Клиент юридическое лицо:

@Entity
public class Customer {

    @Id
    @GeneratedValue
    private long id;
    private String name;
    private String email;

    public Customer(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // getters/setters

}

Кроме того, у нас есть репозиторий JPA:

public interface CustomerRepository extends JpaRepository { 

   // method1
   // method2
}

Мы хотим искать клиентов по имени и электронной почте .

Для этой цели мы напишем два метода, которые по-разному обрабатывают параметры null .

3. Способы обработки нулевых параметров

Во-первых, мы создадим метод , который интерпретирует null значения параметров как РАВНО NULL , а затем мы создадим метод, который игнорирует null параметры и исключает их из предложения WHERE.

3.1. ЯВЛЯЕТСЯ ЛИ запрос NULL

Первый метод очень прост в создании, потому что null параметры в методах запроса по умолчанию интерпретируются как IS NULL|/.

Давайте создадим метод:

List findByNameAndEmail(String name, String email);

Теперь, если мы передадим null email, сгенерированный JPQL будет содержать условие IS NULL :

customer0_.email is null

Чтобы продемонстрировать это, давайте создадим тест.

Во – первых, мы добавим несколько клиентов в репозиторий:

@Before
public void before() {
    entityManager.persist(new Customer("A", "[email protected]"));
    entityManager.persist(new Customer("D", null));
    entityManager.persist(new Customer("D", "[email protected]"));
}

Теперь давайте передадим “D” в качестве значения параметра name и null в качестве значения параметра email в наш метод запроса. Мы видим, что будет найден ровно один клиент:

List customers = repository.findByNameAndEmail("D", null);

assertEquals(1, customers.size());

Customer actual = customers.get(0);

assertEquals(null, actual.getEmail());
assertEquals("D", actual.getName());

3.2. Избегайте Нулевого Параметра С Помощью Альтернативных Методов

Иногда мы хотим игнорировать некоторые параметры и не включать соответствующие им поля в предложение WHERE .

Мы можем добавить дополнительные методы запросов в наш репозиторий. Например, чтобы игнорировать email , мы можем добавить метод, который принимает только name :

 List findByName(String name);

Но такой способ игнорирования одного из наших столбцов плохо масштабируется по мере увеличения числа, так как нам придется добавить много методов для достижения всех комбинаций.

3.3. Игнорирование нулевых параметров С помощью аннотации @Query

Мы можем избежать создания дополнительных методов, используя аннотацию @Query и добавив небольшое усложнение в инструкцию JPQL:

@Query("SELECT c FROM Customer c WHERE (:name is null or c.name = :name) and (:email is null"
  + " or c.email = :email)")
List findCustomerByNameAndEmail(@Param("name") String name, @Param("email") String email);

Обратите внимание, что если параметр: email равен null :

:email is null or s.email = :email

Тогда предложение всегда истинно и поэтому не влияет на все предложение WHERE .

Давайте убедимся, что это работает:

List customers = repository.findCustomerByNameAndEmail("D", null);

assertEquals(2, customers.size());

Мы нашли двух клиентов, чье имя “D” игнорирует их электронные письма.

Сгенерированное предложение JPQL WHERE выглядит следующим образом:

where (? is null or customer0_.name=?) and (? is null or customer0_.email=?)

С помощью этого метода мы доверяем серверу базы данных, чтобы распознать предложение о том, что наш параметр запроса является null , и оптимизировать план выполнения запроса, чтобы он не имел значительных накладных расходов на производительность. Для некоторых запросов или серверов баз данных, особенно связанных с огромным сканированием таблиц, могут возникнуть накладные расходы на производительность.

4. Заключение

Мы продемонстрировали, как Spring Data JPA интерпретирует параметры null в методах запроса, и показали, как изменить поведение по умолчанию.

Возможно, в будущем мы сможем указать, как интерпретировать параметры null , используя аннотацию @NullMeans . Обратите внимание, что в настоящее время это предлагаемая функция, которая все еще находится на рассмотрении.

Подводя итог, можно сказать, что существует два основных способа интерпретации параметров null , и оба они будут предоставлены предложенной аннотацией @Nullmean :

  • IS (is null) – параметр по умолчанию, показанный в разделе 3.1.
  • ИГНОРИРУЕТСЯ (исключить параметр null из предложения WHERE ) – достигается либо с помощью дополнительных методов запроса (раздел 3.2.), либо с помощью обходного пути (раздел 3.3.)

Как обычно, полный исходный код доступен на GitHub .