Убедитесь, что параметр List является нулевым в запросе JPA данных Spring - PullRequest
0 голосов
/ 03 января 2019

У меня есть Spring Boot приложение и я использую Spring Data JPA для запроса MySQL базы данных.

Мне нужно получить список курсов, отфильтрованных по некоторым параметрам.

Я обычно использую синтаксис param IS NULL or (/*do something with param*/), чтобы он игнорировал параметр, если он нулевой.

С простыми типами данных у меня нет проблем, но когда дело доходит до Списка объектов, я не знаю, как проверить значение NULL. Как я могу проверить, является ли параметр ?3 NULL в следующем запросе?

@Query("SELECT DISTINCT c FROM Course c\n" +
       "WHERE c.courseDate < CURRENT_TIME\n" +
       "AND (?1 IS NULL OR (c.id NOT IN (3, 4, 5)))\n" +
       "AND (?2 IS NULL OR (c.title LIKE ?2 OR c.description LIKE ?2))\n" +
       "AND ((?3) IS NULL OR (c.category IN ?3)) ")
List<Course> getCoursesFiltered(Long courseId, String filter, List<Category> categories);

Ошибка:

не удалось извлечь ResultSet; SQL [н / п]; вложенным исключением является org.hibernate.exception.DataException: не удалось извлечь ResultSet [SQL: 1241, 21000]

И в трассировке стека я вижу:

Причина: java.sql.SQLException: операнд должен содержать 1 столбец (столбцы)

Действительно сгенерированный запрос будет ... AND ((?3, ?4, ?5) IS NULL OR (c.category IN (?3, ?4, ?5))), если мой список содержит 3 элемента. Но IS NULL нельзя применить к нескольким элементам (запрос работает нормально, если мой список содержит только один элемент).

Я пытался size(?3) < 1, length(?3) < 1, (?3) IS EMPTY и т. Д., Но все еще не повезло.

Ответы [ 2 ]

0 голосов
/ 04 января 2019

ОК. Я проснулся после пробуждения среди ночи:

@Query("SELECT DISTINCT c FROM Course c\n" +
       "WHERE c.courseDate < CURRENT_TIME\n" +
       "AND (?1 IS NULL OR (c.id NOT IN (3, 4, 5)))\n" +
       "AND (?2 IS NULL OR (c.title LIKE ?2 OR c.description LIKE ?2))\n" +
       "AND (COALESCE(?3) IS NULL OR (c.category IN ?3)) ")
List<Course> getCoursesFiltered(Long courseId, String filter, List<Category> categories);

Решение было просто использовать COALESCE в дополнение к IS NULL, чтобы он мог работать с несколькими значениями,Таким образом, если список содержит хотя бы одно ненулевое значение, второе выражение ((c.category IN ?3)) выполнит фильтрацию.

В следующий раз я подожду хотя бы целую ночь, прежде чем задать вопрос:)

0 голосов
/ 03 января 2019

Это не дает точного ответа на ваш вопрос, но одно простое решение состоит в том, чтобы в вашем хранилище был другой метод, который проверяет ваши списки перед вызовом запроса и устанавливает по умолчанию их в список с фиктивным значением.Что-то вроде:

@Query("SELECT DISTINCT c FROM Course c\n" +
       "WHERE c.courseDate < CURRENT_TIME\n" +
       "AND (?1 IS NULL OR (c.id NOT IN (3, 4, 5)))\n" +
       "AND (?2 IS NULL OR (c.title LIKE ?2 OR c.description LIKE ?2))\n" +
       "AND ('DUMMYVALUE' IN ?3 OR (c.category IN ?3)) ")
// make this private to keep it safe
private List<Course> getCoursesFiltered(Long courseId, String filter, List<Category> categories);

// public helper method to put a dummy value in the list that you can check for
public List<Course> getNullableCoursesFiltered(Long courseId, String filter, List<Category> categories) {
    if(categories == null) {
        categories = Arrays.asList("DUMMYVALUE");
    }
    return getCoursesFiltered(courseId, filter, categories);
}
...