Using the unsaved-value attribute to prevent TransientObjectExceptions in Hibernate

Age Mooij

We ran into a TransientObjectException in our Hibernate-enabled code. At first the exception was very hard to reproduce and only occured in very rare cases. Sometimes during our integration tests and sometimes during our smoke tests.

We tried just about everything to find out why Hibernate interpreted the relevant objects as being unsaved (ie transient) even though we verified that they were indeed saved in a previous Hibernate Session by looking at the sql logging.

It turns out that Hibernate does not see the diffference between the values "0" and "null" when looking at the ID property (a java.lang.Long) to check whether the object is persistent. Because our Oracle sequence starts at 0, the first object that was persisted had an ID of 0. When that object was then used in a later Session, Hibernate did not recognize that value as valid and interpreted the object as transient.

We fixed this by adding an extra unsaved-value attribute to the relevant mapping. Like so:

<id column="ID" name="id" type="java.lang.Long" unsaved-value="null" length="10">
  <generator class="native">
    <param name="sequence">MY_SEQ</param>

That solved the problem. Whether this is a bug or a feature in Hibernate I'll leave as an exercise for the readers 🙂

Comments (6)

  1. Lars Vonk - Reply

    August 11, 2006 at 11:02 pm

    This is probably an undocumented feature.The hibernate doc says:
    "unsaved-value (optional - defaults to a "sensible" value)" and "The unsaved-value attribute is almost never needed in Hibernate3.". Well indeed almost...

  2. Serge Beaumont - Reply

    August 12, 2006 at 8:50 pm

    IMHO it is a bug. I don't know Hibernate 3, but in 2 the unsaved value was essentially the same as whatever Java initializes an instance variable to when you don't provide an initializer:

    String blah;

    would mean a null value. int initializes to 0, etcetera. A Long initialized to 0 at least breaks backwards compaltibility.

  3. Casper Groenen - Reply

    August 28, 2006 at 5:05 pm

    Maybe, you should let your sequences start at 1 (which most DBMSes do anyway).

  4. Maarten Winkels - Reply

    August 29, 2006 at 8:33 am

    Casper, you're probably right about using sequence numbers that start at 1 when using them for valus in a column. The tricky thing is, that when using Hibernates HiLoSequenceGenerator (too decrease load on the database when inserting a lot of records in a table with a PK based on a sequence), it uses the sequence to generate a range of numbers. The transformation maps the value of 0 to the range [ 1 - range_size+1], thus when range_size = 999, a sequnce that starts at 0 will produce the numbers [1 - 1000] first and then [1001 - 2000]. A sequence that starts at 1 will first returns numbers in the range [1001 - 2000], thus leaving a gap at the start.
    In our case we mix IdGenerators, since some objects are persisted more often than others, we use simple SequenceGenerators for these types. These should be used with sequences that start at 1.

  5. Yashashree - Reply

    May 20, 2010 at 10:09 am

    I am getting exception as "PersistenceException: Unable to add new object to the datastore", when i am adding new values in one of my tables using hibernate pojo class having unsaved-value=null. Can you people tell me whether this exception is related to that unsaved-value attribute??.

  6. Age Mooy - Reply

    May 21, 2010 at 3:00 pm

    Dude, this was way back in 2006 and I haven't used Hibernate in years. Your problem description is way to vague to determine any specific cause. I suggest Google and/or the manual.

Add a Comment