3

Short Description

How do I make findBy<Field>In work with IN when the array list input is null. e.g. ignore it. What would your DAO for this look like?

Longer description.

Imagine you have creating a search for users page.

in the application. You have various options to filter on.

  • created (date range always given)
  • Country (when null ignore and search all countries)
  • AgeRange
  • Job Title
  • etc...

Now say you want to search for all users in a given date range in a list of countries.

When searching for users I will always search for a date joined however if I have not selected a country I want it to search for all countries.

I am planning on adding several more filter options other than country. So I don't really want to create lots of findBy methods for each possible field combination.

DAO

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

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

}

Test

@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);

}
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
Robbo_UK
  • 11,351
  • 25
  • 81
  • 117

1 Answers1

0

You can have two methods:

beatRateDao.findByCreatedBetweenAndRentalCountryIn(from, to, countryList);

and

beatRateDao.findByCreatedBetweenAndRental(from, to);

Then simply pick one based on countryList:

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

The IN clause requires a non-nullable and non empty argument list as otherwise the query will fail.

On PostgreSQL, if you try to run a query like this:

select * 
from product 
where quantity in ( )

you get the following error:

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

ERROR: syntax error at or near ")"
SQL state: 42601
Character: 45
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • Thanks for the reply.. The problem is I have several filters. Status, Country, City, Users... Sometimes Country exists sometimes not sometimes you want Status and Country but not City.. etc.. It results in a lot of combinations so im not sure the above method is the best way?. – Robbo_UK Mar 06 '15 at 13:54
  • 1
    Criteria API works best for dynamic filters. Spring Data doesn't work with null arguments. – Vlad Mihalcea Mar 06 '15 at 13:58
  • what is Criteria API? – Robbo_UK Mar 06 '15 at 14:00
  • [Criteria API](http://docs.oracle.com/javaee/6/tutorial/doc/gjitv.html) is a JPA type-safe dynamic query builder API. – Vlad Mihalcea Mar 06 '15 at 14:03
  • @VladMihalcea is correct. You should check out [this other question](http://stackoverflow.com/questions/28884192/best-way-to-create-jpa-query-that-might-contain-a-parameter-or-might-not/). – Schaka Mar 06 '15 at 14:56
  • 1
    If you want to construct a query based on arbitrary constraints I recommend to look into [Querydsl](http://querydsl.com/). It's by far the nicest API to assemble predicates on the fly. Spring Data derived query methods are rather targeted to use cases where you have a static set of constraints. See [this blog post](https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/) on Spring Data integration with Querydsl. – Oliver Drotbohm Mar 07 '15 at 13:18
  • @OliverDrotbohm I have the exact same issue. Multiple findBy In List criterias which can be null. Is your comment still valid for 2020 or would you use an other approach today? – timguy Apr 29 '20 at 13:51