-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Handling of NULL and empty string "" by Hibernate
PostPosted: Fri Dec 17, 2010 7:58 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Hi,

Hibernate is puzzling me a bit regarding its handling of NULL and "" empty string values.

The Criteria API based following statement:
Code:
Restrictions.ne("course", "")

seems to consider NULL values as "" empty ones.

Indeed I have an entity set up as:
Code:
   private String course;

Code:
        <property name="course" type="string">
            <column name="course" />
        </property>


My current Dao implementation does not explicitly consider NULL values:
Code:
   public List<ContentImportHistory> findWithCourseContent() {
      Criteria criteria = getSession().createCriteria(getPersistentClass());
      criteria.add(Restrictions.ne("course", ""))
      .addOrder(Order.asc("domainName")).addOrder(Order.desc("importDatetime"));
      return criteria.list();
   }


And the test works just fine:
Code:
      contentImportHistory0 = new ContentImportHistory();
      contentImportHistory0.setDomainName(domainName0);
      contentImportHistory0.setCourse(course);
      DateTime importDatetime = new DateTime();
      contentImportHistory0.setImportDatetime(importDatetime);
      contentImportHistory0bis = new ContentImportHistory();
      contentImportHistory0bis.setDomainName(domainName0);
      contentImportHistory0bis.setImportDatetime(importDatetime);
      contentImportHistory0bis.setCourse(null);
...
      contentImportHistory0 = contentImportHistoryDao.makePersistent(contentImportHistory0);
      contentImportHistory0bis = contentImportHistoryDao.makePersistent(contentImportHistory0bis);
...
   public void testFindWithCourseContent() {
      List<ContentImportHistory> contentImportHistories = contentImportHistoryDao.findWithCourseContent();
      assertEquals(1, contentImportHistories.size());
      assertEquals(course, contentImportHistories.get(0).getCourse());
   }


Clearly, the explicitly set null value in:
Code:
contentImportHistory0bis.setCourse(null);

was not considered to be not equal to "".


Now, if I take another table and another Dao, things seem to be a bit different...

This time the Criteria API based following statement:
Code:
Restrictions.eq("language", "")

seems to NOT consider NULL values as "" empty ones.

Notice the use of eq() instead of the previous ne() method.

Indeed I have an entity set up as:
Code:
   private String language;

Code:
        <property name="language" type="string">
            <column name="language" length="2" />
        </property>


This time, my current Dao implementation HAS TO explicitly consider NULL values:
Code:
   public NavbarLanguage findByNavbarAndNoLanguage(Navbar navbar) {
      Criteria criteria = getSession().createCriteria(getPersistentClass());
      criteria.add(Restrictions.eq("navbar", navbar));
      criteria.add(Restrictions.or(Restrictions.isNull("language"), Restrictions.eq("language", "")));
      return (NavbarLanguage) criteria.uniqueResult();
   }


Notice the addition of:
Code:
Restrictions.isNull("language")


And the test works just fine:
Code:
      navbar0 = new Navbar();
      navbarLanguage0 = new NavbarLanguage();
      navbarLanguage0.setLanguage("en");
      navbar0.addNavbarLanguage(navbarLanguage0);
      navbarLanguage1 = new NavbarLanguage();
      navbarLanguage1.setLanguage("fr");
      navbar0.addNavbarLanguage(navbarLanguage1);
      navbarLanguage2 = new NavbarLanguage();
      navbarLanguage2.setLanguage("se");
      navbar0.addNavbarLanguage(navbarLanguage2);
      navbarLanguage3 = new NavbarLanguage();
      navbar0.addNavbarLanguage(navbarLanguage3);
..
      navbar0 = navbarDao.makePersistent(navbar0);
..
   public void testFindByNavbarAndNoLanguage() {
      NavbarLanguage navbarLanguage = navbarLanguageDao.findByNavbarAndNoLanguage(navbar0);
      assertEquals(navbarLanguage3.getLanguage(), navbarLanguage.getLanguage());
      navbarLanguage3.setLanguage("");
      navbarLanguage = navbarLanguageDao.findByNavbarAndNoLanguage(navbar0);
      assertEquals(navbarLanguage3.getLanguage(), navbarLanguage.getLanguage());
   }


But if the Dao was implemented without the explicit handling of NULL values as in:
Code:
   public NavbarLanguage findByNavbarAndNoLanguage(Navbar navbar) {
      Criteria criteria = getSession().createCriteria(getPersistentClass());
      criteria.add(Restrictions.eq("navbar", navbar));
      criteria.add(Restrictions.eq("language", ""));
      return (NavbarLanguage) criteria.uniqueResult();
   }

then the test would give me the following exception:
Code:
java.lang.NullPointerException

for no entity would be found.

In this case, the NULL value is not considered to be equal to "".

So, to sum this all up, why when doing a ne() is the NULL considered a "" and when doing an eq() the NULL is not considered a "" ?


Top
 Profile  
 
 Post subject: Re: Handling of NULL and empty string "" by Hibernate
PostPosted: Fri Dec 17, 2010 9:39 am 
Senior
Senior

Joined: Fri May 08, 2009 12:27 pm
Posts: 168
This is really SQL logic. NULL is neither equal nor inequal to an empty string (or to anything else for that matter).

Think of NULL as "might be any value, the database doesn't know".
And of = as "the database knows this is equal", so is NULL = 'whatever' true? No it isn't, the database does not know for sure.
!= means "the database knows this is inequal", so we don't have NULL != 'whatever' either, because the database can't be sure that the unknown value behind NULL is definitely inequal to 'whatever'.

Of course, in practice, NULL is often used as "the database knows that there is no good value here", or "it is known that no data exists here". That's just not the logic that = and != were defined for.

As you wrote, you need to explicitly use isNull to handle the NULL case.
In Mysql, there's an extra == operator that uses the "the database knows that there is no applicable value" semantics. Such an operator never made it into the SQL standard, unfortunately.
(And yes, your problem is an SQL FAQ.)


Top
 Profile  
 
 Post subject: Re: Handling of NULL and empty string "" by Hibernate
PostPosted: Fri Dec 17, 2010 10:43 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Thanks for that richly detailed explaining !

I shall explicitly use a isNull statement then.

Cheers.


Top
 Profile  
 
 Post subject: Re: Handling of NULL and empty string "" by Hibernate
PostPosted: Sun Dec 19, 2010 10:58 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
I have now added an explicit check against the possibility of a null value instead of an "" empty one.

Code:
Restrictions.and(Restrictions.ne("course", ""), Restrictions.isNotNull("course"))


Top
 Profile  
 
 Post subject: Re: Handling of NULL and empty string "" by Hibernate
PostPosted: Mon Dec 20, 2010 10:28 am 
Senior
Senior

Joined: Fri May 08, 2009 12:27 pm
Posts: 168
Nice to hear that it works :-)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.