JPA-запрос для обработки значения параметра NULL

Я новичок в JPA, вот один из моих запросов, и у меня есть несколько параметров, как часть запроса, и любой параметр может иметь нулевое значение

@Query(value = "SELECT ord.purchaseOrderNumber,ord.salesOrderNumber,ord.quoteNumber"

            + " FROM Order ord WHERE ord.purchaseOrderNumber LIKE :poNumber%  "
            + " AND ord.salesOrderNumber LIKE :soNumber "
            + " AND ord.quoteNumber = :quoteNumber "

В приведенном выше примере, если мой входной параметр: quoteNumber равен NULL, я не должен фильтровать по ord.quoteNumber = NULL, так как этого избежать

9 ответов

Вы можете добавить набор условий, чтобы "игнорировать" свойства с нулевыми значениями или пустыми строками.

например

+ " AND (ord.quoteNumber = :quoteNumber or :quoteNumber is null or :quoteNumber = '' ")

Для параметров, допускающих значение NULL, вы можете сделать что-то вроде:

@Query(value = "SELECT ord.purchaseOrderNumber,ord.salesOrderNumber,ord.quoteNumber"
        + " FROM Order ord "
        + " WHERE (:poNumber is NULL OR ord.purchaseOrderNumber LIKE :poNumber)"
        + " AND (:soNumberis NULL OR ord.salesOrderNumber LIKE :soNumber)"
        + " AND (:quoteNumber is NULL OR ord.quoteNumber = :quoteNumber) "

К сожалению, сравнение = не работает с нулевыми значениями, для этого у вас есть предикат IS NULL, NOT NOT NULL. Что это означает, что вам нужны разные запросы для случаев, когда вы цитируете null и нет. Вы можете проверить NULL в своем коде Java, а затем выбрать правильный запрос для вызова. Если номер oder, quote не может быть пустыми строками ("") (что они не должны), то вы можете представить отсутствие данного числа в виде пустой строки и всегда использовать нормальное сравнение. Просто запомните настройку схемы БД, чтобы столбцы не могли быть нулевыми и значения по умолчанию для них были "". Кстати, ваши имена столбцов предлагают цифры, но вы используете сравнение строк, я надеюсь, что это нормально.

Если nullдопустимый параметр,

      ... AND ((:param is null and param is null) or (:param is not null and param = :param)) AND ...

Мы можем избежать создания дополнительных методов, используя аннотацию @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:

:email is null or s.email = :emailТогда предложение всегда истинно и не влияет на все предложение WHERE.

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

List<Customer> customers = repository.findCustomerByNameAndEmail("D", null);
 
assertEquals(2, customers.size());

Мы нашли двух клиентов по имени "D", игнорирующих свои электронные письма.

Сгенерированное предложение JPQL WHERE выглядит так:

где (? равно null или customer0_.name=?) и (? is null или customer0_.email=?) С помощью этого метода мы доверяем серверу базы данных распознать предложение о том, что параметр нашего запроса имеет значение NULL, и оптимизировать выполнение план запроса, чтобы он не имел значительных накладных расходов на производительность. Для некоторых запросов или серверов баз данных, особенно при сканировании огромных таблиц, могут возникнуть накладные расходы на производительность.

Если вы хотите проверить, что параметр имеет нулевое или пустое значение, вы должны сделать следующее:

      @Query("SELECT t FROM Test t WHERE (t.parameterOne = :parameterOne  OR ((:parameterOne IS NULL) OR (:parameterOne = ''))");

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

И (ord.quoteNumber = :quoteNumber или ord.quoteNumber равно null")

С java17 и jpa2.6> это сработало для меня.

Что вы можете сделать, сначала приведите нулевой параметр к тексту, а затем ОБЪЕДИНИТЕ его с пустыми строками, чтобы ваш запрос стал @Query (value = "SELECT ord.purchaseOrderNumber, ord.salesOrderNumber, ord.quoteNumber"

              + " FROM Order ord WHERE COALESCE(ord.purchaseOrderNumber,'') LIKE COALESCE(cast(:poNumber% As TEXT),'') "
        + " AND COALESCE(ord.salesOrderNumber,'') LIKE COALESCE(cast(:soNumber As TEXT),'') "
        + " AND COALESCE(ord.quoteNumber,'') = COALESCE(cast(:quoteNumber As TEXT),'') "

Вы можете использовать что-то вроде этого:quoteNumber = -999 AND ord.quoteNumber =:quoteNumber

и передайте -999 на запрос, если вы хотите передать ноль.

Я пытаюсь увидеть, можете ли вы по умолчанию установить -999, используя @parma

Другие вопросы по тегам