Автор оригинала: 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|/.
Давайте создадим метод:
ListfindByNameAndEmail(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 в наш метод запроса. Мы видим, что будет найден ровно один клиент:
Listcustomers = 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 :
ListfindByName(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)") ListfindCustomerByNameAndEmail(@Param("name") String name, @Param("email") String email);
Обратите внимание, что если параметр: email равен null :
:email is null or s.email = :email
Тогда предложение всегда истинно и поэтому не влияет на все предложение WHERE .
Давайте убедимся, что это работает:
Listcustomers = 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 .