Репозиторий Spring JPA findBy IN List - разрешить ноль

Краткое описание

Как заставить findBy<Field>In работать с IN, когда ввод списка массивов равен нулю. например игнорируй это. Как будет выглядеть ваш DAO для этого?

Подробнее описание.

Представьте, что вы создали страницу поиска пользователей.

в приложении. У вас есть различные варианты фильтрации.

  • создано (всегда указан диапазон дат)
  • Страна (при нулевом значении игнорировать и искать все страны)
  • Возрастной диапазон
  • Название работы
  • и т.д...

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

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

Я планирую добавить еще несколько параметров фильтра, кроме страны. Поэтому я действительно не хочу создавать множество методов findBy для каждой возможной комбинации полей.

ДАО

@Repository
public interface UserDao extends JpaRepository<User, Long> {

    public List<BeatRate> findByCreatedBetweenAndCountryIn(Date from, Date to, ArrayList<String> countryList );

}

Тест

@Test
public void test() throws ParseException {

    Date from = new SimpleDateFormat( "yyyy-MM-dd" ).parse( "2015-01-01" );
    Date to   = new SimpleDateFormat("yyyy-MM-dd").parse("2015-05-15");

    //ArrayList<String> countryList = new ArrayList<String>();
    //countryList.add("UK");
    //countryList.add("Australia");
    //countryList.add("Japan");   // works ok when I have a list

    countryList = null;  // I want it to search for all countries when this is null -- this errors and doesnt work..  

    List<BeatRate> beatRates = beatRateDao.findByCreatedBetweenAndRentalCountryIn(from, to, countryList);

    Assert.assertTrue(beatRates.size()>0);

}

person Robbo_UK    schedule 06.03.2015    source источник


Ответы (1)


У вас может быть два метода:

beatRateDao.findByCreatedBetweenAndRentalCountryIn(from, to, countryList);

и

beatRateDao.findByCreatedBetweenAndRental(from, to);

Затем просто выберите один на основе countryList:

List<BeatRate> beatRates = (countryList != null && !countryList.isEmpty())
    ?  beatRateDao.findByCreatedBetweenAndRentalCountryIn(from, to, countryList)
    : beatRateDao.findByCreatedBetweenAndRental(from, to);

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

В PostgreSQL, если вы попытаетесь выполнить такой запрос:

select * 
from product 
where quantity in ( )

вы получаете следующую ошибку:

ERROR:  syntax error at or near ")"
LINE 3: where quantity in ( )
                            ^
********** Error **********

ERROR: syntax error at or near ")"
SQL state: 42601
Character: 45
person Vlad Mihalcea    schedule 06.03.2015
comment
Спасибо за ответ. Проблема в том, что у меня несколько фильтров. Статус, Страна, Город, Пользователи... Иногда Страна существует, иногда нет, иногда вам нужны Статус и Страна, но не Город.. и т.д.. Это приводит к множеству комбинаций, поэтому я не уверен, что описанный выше метод является лучшим способом? - person Robbo_UK; 06.03.2015
comment
Criteria API лучше всего работает с динамическими фильтрами. Spring Data не работает с нулевыми аргументами. - person Vlad Mihalcea; 06.03.2015
comment
что такое критерии API? - person Robbo_UK; 06.03.2015
comment
Criteria API – это безопасный для JPA API построителя динамических запросов. . - person Vlad Mihalcea; 06.03.2015
comment
@VladMihalcea прав. Вы должны проверить этот другой вопрос. - person Schaka; 06.03.2015
comment
Если вы хотите построить запрос на основе произвольных ограничений, я рекомендую изучить Querydsl. На сегодняшний день это лучший API для сборки предикатов на лету. Методы запросов, производные от Spring Data, скорее предназначены для использования в случаях, когда у вас есть статический набор ограничений. См. эту запись в блоге об интеграции Spring Data с Querydsl. - person Oliver Drotbohm; 07.03.2015
comment
@OliverDrotbohm У меня точно такая же проблема. Несколько критериев findBy In List, которые могут быть нулевыми. Ваш комментарий все еще актуален для 2020 года или вы бы использовали другой подход сегодня? - person timguy; 29.04.2020