Search code examples
hibernatehql

How to check if a collection parameter is null in hql?


So How to check if a collection is null in HQL? Simple example:

select * from Book book where title in (:titles)

So if titles is a single variable, I can do

select * from Book book where (:titles is null or title in (:titles))

But what if titles is a list/collection?

select * from Book book where (:titles is null or title in (:titles))

this won't work if titles is a list. After intense search, I tried is empty, size, and exists function, I also tried (:titles) is null option.

None of the above works. I know there is a hard coded way which is writing different query depends on the status of the titles list, if it is null, one query, and if it is null, another query. But that will produce a lot similar HQL queries with minor changes. And my use cases has few more lists to consider so it is not desired.

My question is it even possible to do the checking directly in HQL?


Solution

  • :titles is a list.
    You want to search books, which have theses "titles".

    The user,

    • Might have select one title
    • Might have selected multiple titles
    • Or might have selected no titles at all

    So this list might be null, might have one or more elements in it.

    In any case, you will use Query.setParameterList(), in order to pass the titles collection into the query, as described in this answer.

    Now then, you wouldn't want to use a set method, if the parameter you are trying to pass could be null. After all it's Java that we are talking on here.

    So, what you need, is to check if this list is null or not.
    Also, you do not want to have hibernate check if the list of titles, that the user has selected, is null.
    You also need to have one query only, there is no need for multiple queries.

    The way to do this is by using a query builder.
    There are many ways to implement this methodology. But in general the idea is that you

    • Either use a framework, specialized for these kind of jobs, like Querydsl, check here
    • Or you simple use a StringBuilder to build the select, from and where clauses of your query, for example:

      Map<String,Object> params = new HashMap<String,Object>();
      StringBuilder queryBuilder = new StringBuilder();
      queryBuilder.append(" from Book book ");
      if(!titlesList.isEmpty()){
          queryBuilder.append(" where book.title in (:titles) ");
          params.put("titles", titlesList);
      }
      Query query = entityManager.createQuery(queryBuilder.toString());
      for ( Map.Entry<String,Object>; param : params.entrySet()) {
          if(param instanceof Collection<?>){
              query.setParameterList(param.getKey(),param.getValue());
          }
          //if param is of type String then query.setString etc. 
          //else setParameter, you get the idea, use the docs
      }
      List<Book> results = (List<Book>) query.list();