Перейти к основному содержимому

Spring Data JPA и нулевые параметры

· 4 мин. чтения

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

1. Обзор

В этом руководстве мы покажем, как обрабатывать нулевые параметры в Spring Data JPA .

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

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

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

Допустим, у нас есть сущность Customer :

@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<Customer, Long> { 

// method1
// method2
}

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

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

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

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

3.1. ЕСТЬ НУЛЕВОЙ запрос

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

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

List<Customer> findByNameAndEmail(String name, String email);

Теперь, если мы передаем нулевое электронное письмо, сгенерированный JPQL будет включать условие IS NULL :

customer0_.email is null

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

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

@Before
public void before() {
entityManager.persist(new Customer("A", "A@example.com"));
entityManager.persist(new Customer("D", null));
entityManager.persist(new Customer("D", "D@example.com"));
}

Теперь давайте передадим «D» в качестве значения параметра имени и null в качестве значения параметра электронной почты в наш метод запроса.

Мы видим, что будет найден ровно один клиент:

List<Customer> 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 .

Мы можем добавить больше методов запроса в наш репозиторий.

Например, чтобы игнорировать электронную почту , мы можем добавить метод, который принимает только имя :

List<Customer> 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<Customer> findCustomerByNameAndEmail(@Param("name") String name, @Param("email") String email);

Обратите внимание, что если параметр email равен null , предложение всегда истинно и поэтому не влияет на все предложение WHERE :

:email is null or s.email = :email

Убедимся, что это работает:

List<Customer> 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 интерпретирует нулевые параметры в методах запросов и как изменить поведение по умолчанию.

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

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

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

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