views:

1949

answers:

4

Hello,

how can I set a Hibernate Parameter to "null"? Example:

Query query = getSession().createQuery("from CountryDTO c where c.status = :status  and c.type =:type")
.setParameter("status", status, Hibernate.STRING)
.setParameter("type", type, Hibernate.STRING);

In my case, the status String can be null. I have debugged this and hibernate then generates an SQL string/query like this ....status = null... This however does not Work in MYSQL, as the correct SQL statement must be "status is null" (Mysql does not understand status=null and evaluates this to false so that no records will ever be returned for the query, according to the mysql docs i have read...)

My Questions:

  1. Why doesnt Hibernat translate a null string correctly to "is null" (and rather and wrongly creates "=null")?

  2. What is the best way to rewrite this query so that it is null-safe? With nullsafe I mean that in the case that the "status" String is null than it should create an "is null"?

Thank you very much! Tim

+1  A: 

The javadoc for setParameter(String, Object) is explicit, saying that the Object value must be non-null. It's a shame that it doesn't throw an exception if a null is passed in, though.

An alternative is setParameter(String, Object, Type), which does allow null values, although I'm not sure what Type parameter would be most appropriate here.

skaffman
Hello skaffman. Thank you very much for your help! When asking the question I actually thought I am just to silly to find a solution. But its seems that this is a real "oddity" of hibernate. Most likely I will have to write my own Nullable-String-Type or I will have to switch to Criteria Queries... After digging deeper it seems that the current implementation of the Hibernat.STRING Type is not nullable:http://www.docjar.com/html/api/org/hibernate/type/StringType.java.html. (But shouldn't the MySQL JConnector implement the PreparedStatment.setString correctly??) Thanks Tim.
tim
Just for information, it's actually a "feature" of JDBC: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4312435Hibernate uses JDBC's `PreparedStatement.setNull()` to bind `null` parameters
axtavt
A: 

I did not try this, but what happens when you use :status twice to check for NULL?

Query query = getSession().createQuery(
     "from CountryDTO c where ( c.status = :status OR ( c.status IS NULL AND :status IS NULL ) ) and c.type =:type"
)
.setParameter("status", status, Hibernate.STRING)
.setParameter("type", type, Hibernate.STRING);
Peter Lang
Hellp Peter, thank you very much for you help! I dont know why, but it seems that hibernate always evaluates the ( c.status = :status OR ( c.status IS NULL AND :status IS NULL ) to c.status = null (according to my mysql query log). I also changed the order to (( c.status IS NULL AND :status IS NULL ) OR c.status = :status) with the same result. Thanks Tim
tim
+3  A: 

1. I believe hibernate first translates your HQL query to SQL and only after that it tries to bind your parameters. Which means that it won't be able to rewrite query from param = ? to param is null.

2. Try using Criteria api:

Criteria c = session.createCriteria(CountryDTO.class);
c.add(Restrictions.eq("type", type));
c.add(status == null ? Restrictions.isNull("status") : Restrictions.eq("status", status));
List result = c.list();
Sergey Demin
Hello Sergey, Thanks for your answer. I actually implemented it (already before you posted your answer) also with the Criteria API. But I nevertheless think this is not the "ideal solution" to the problem. Ok to be honest, sometimes "oddities/bugs" do not have a real good solution....I have marked your answer as the "solution" to to problem.
tim
you are welcome :)but what do you expect from ideal solution? if you are fine with criteria api instead of hql, you can always create your own factory method for 'null-safe' Criterion.
Sergey Demin
+1  A: 

It seems you have to use is null in the HQL, (which can lead to complex permutations if there are more than one parameters with null potential.) but here is a possible solution:

String statusTerm = status==null ? "is null" : "= :status";
String typeTerm = type==null ? "is null" : "= :type";

Query query = getSession().createQuery("from CountryDTO c where c.status " + statusTerm + "  and c.type " + typeTerm);

if(status!=null){
    query.setParameter("status", status, Hibernate.STRING)
}


if(type!=null){
    query.setParameter("type", type, Hibernate.STRING)
}
Ehrann Mehdan
Looks like old sql query building to me. Stick to the criteria api for stuff like this. Hand written hql is extremely error prone.
Willi