Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate restriction in causes an error if the list is empty

Tags:

java

hibernate

If my list is empty, I get the following error:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')'

Below is my hibernate related method:

  @Override
    public List<SomeThing> findByIds(List<Integer> someIds) {
        return sessionFactory.getCurrentSession().createCriteria(SomeClass.class)
                .add(Restrictions.in("id", someIds))
                .list();
    }

What should I do to guard against this error?

I know I could short-circuit the call and return an empty list like:

if(someIds == null || someIds.size() == 0) {
  return new List<SomeThing>();
}

But is there a more elegant way to do this?

like image 786
Blankman Avatar asked Oct 22 '12 02:10

Blankman


People also ask

Does hibernate return null or empty list?

Hibernate would know that there is no phone for the employee but returning null instead of an empty list, which also would express that there are no phones, would still make little sense (think of allowing to add phones for a loaded employee, differences in code where you'd not need them if null was used for eager ...

What is restriction in hibernate criteria?

The Criteria interface makes it easy to selectively fetch the data on the basis of conditions in the select query. The Restriction class in hibernate provide several methods that can be used as conditions (also known as Criterion). These conditions are added to a criteria object with the add() method.


3 Answers

I would say Hibernate needs to fix this issue, and give meaningful message.

I think its responsibility of the provider/hibernate to check for the empty/null List.

One can imagine the cause, it tries to construct where clause, something like id in (), somewhere in org.hibernate.loader.criteria.CriteriaQueryTranslator or similar..But because here the List is empty, it would be throwing an exception. But they already created query with ( and could not complete because of exception/empty List.

like image 115
Maddy Avatar answered Oct 14 '22 12:10

Maddy


NO. If you execute the query with empty parameters for in clause, it will fail (you may verify this by running plain SQL). Better not to execute the query if the input param is null/empty.

Only thing I can advice is to use isEmpty() function and != null in if statement and little restructuring as:

@Override
public List<SomeThing> findByIds(List<Integer> someIds) {
   List<Something> result = null; //you may initialize with empty list
   if(someIds != null || !someIds.isEmpty() {
       result = sessionFactory.getCurrentSession().createCriteria(SomeClass.class)
            .add(Restrictions.in("id", someIds))
            .list();
   } 
   return result;
}
like image 34
Yogendra Singh Avatar answered Oct 14 '22 12:10

Yogendra Singh


(This is mostly base on @Yogendra Singh's reply, with a twist to make it more adoptable to commonly-seen situation of multiple optional argument)

Criteria API aims to let you compose your query programmatically. Such kind of dynamic feature is expected to be handled in your code.

Normally we make optional criteria by this:

@Override
public List<SomeThing> findBySearchParams(SearchParam searchParam) {
   // create criteria with mandatory search criteria
   Criteria criteria = sessionFactory.getCurrentSession()
                           .createCriteria(SomeClass.class);
                           .add(Restriction("someField", searchParam.getSomeField()));


   // add "id" only if "someId" contains value
   if(searchParam.getSomeIds() != null && !searchParam.getSomeIds().empty()) {
       criteria.add(Restrictions.in("id", searchParam.getSomeIds()));
   } 

   // add "anotherField" only if "anOptionalField" is not null
   if(searchParam.getAnOptionalField() != null) {
       criteria.add(Restrictions.in("anotherField", searchParam.getAnOptionalField()));
   } 

   return criteria.list();
}

Edit:

Although Hibernate does not (yet) provide a more elegant way for that, you can write something yourself to make it looks more elegant:

class SmartCriteriaBuilder {
  private Criteria criteria;
  SmartCriteriaBuilder (Criteria criteria) { this.criteria = criteria;}

  SmartCriteriaBuilder in(String field, Collection values) {
    if (!empty(values)) {
      this.criteria.add(Restrictions.in(field,values));
    }
  }
  // all other kind of restrictions ....

  Criteria toCriteria() {
    return this.criteria;
  }
}

Then you can do something looks smarter:

SmartCriteriaBuilder criteriaBuilder = 
    new SmartCriteriaBuilder(sessionFactory.getCurrentSession().createCriteria());

criteriaBuilder .in("someField", listPossiblyNullOrEmpty);


return criteriaBuilder .toCriteria().list();    
like image 21
Adrian Shum Avatar answered Oct 14 '22 11:10

Adrian Shum