-->
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.  [ 6 posts ] 
Author Message
 Post subject: Null-values in Map: 1.x to 2.x difference
PostPosted: Tue Jan 20, 2004 10:33 am 
Newbie

Joined: Tue Jan 20, 2004 10:27 am
Posts: 2
Hi,

We are currently trying to upgrade from Hibernate 1.25 to Hibernate 2.1.1. This seems to be straight-forward and well-documented. However, we have run into a rather surprising difference in the way Maps with null-values are dealt with.

We have been using Hibernate for about a year now, in a medium-sized web-application that has been in production for a few months. We really like it and we plan to use it for a long time, so we would like to upgrade to the newest version.

The problem we find is that in Hibernate 1 it is possible to store null as a value in a persistent Map, and in Hibernate 2 this doesn't seem to work: the Map entry containing the null-value is silently discarded. In our application a null-value has a meaning; leaving it out of the map is not trivial.

My questions are: is this known behavior, and how come this has changed between Hibernate 1 and 2? Is there a work-around that always null-values to be stored in a Map anyway?

Thank you for your time!

Guus Bosman,
software engineer, Chess-iT

Our datamodel

A Device has a Map. The keys of this Map are Parameters, its values are java.lang.Strings

Our testcase

The testcase creates a device, and adds the following Map:
Code:
{new Parameter("aNullValue") --> null,
new Parameter("aRegularValue") --> "myValue"}


Below you'll find the relevant code-fragments.

Device.hbm.xml

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
   
<hibernate-mapping>
  <class name="nl.chess.hibernateupgrade.model.Device"
  table="rmgt_device">
    <id name="dbId" type="long">           
         <generator class = "native">           
         </generator>       
      </id>

    <property name="name" not-null="true" />

    <map name="parameterValues" cascade="save-update"
    table="rmgt_parametervalues">
      <key column="id_device_element" />

      <index-many-to-many column="id_parameter"
      class="nl.chess.hibernateupgrade.model.Parameter" />

      <element column="value" type="string" not-null="false" />
    </map>
  </class>
</hibernate-mapping>


Parameter.hbm.xml

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
  <class name="nl.chess.hibernateupgrade.model.Parameter"
  table="rmgt_parameter">
    <id name="dbId" type="long">           
         <generator class = "native">           
         </generator>       
      </id>

    <property name="name" not-null="true" />
  </class>
</hibernate-mapping>


The testcase

Code:
public class ParameterValueTest extends TestCase {
    protected void setUp() throws Exception {
        super.setUp();
        DataModel.recreateDB();
    }

    public void testNullValue() throws Exception {
        prepareTestData();

        ThreadSessionManager.newSession();

        Device device = DeviceDAO.getByName("xx");
        assertNotNull(device);

        Set set = device.getParameterValues().entrySet();
        assertEquals(2, set.size());
        ThreadSessionManager.commitSession();
    }

    /**
     * Adds a device, with a Map with two key-value pairs.
     */
    private void prepareTestData() {
        ThreadSessionManager.newSession();

        Device device5 = new Device("xx");

        Parameter parameterWithNullValue = new Parameter("aNullValue");
        ParameterDAO.add(parameterWithNullValue);

        Parameter parameterWithRegularValue = new Parameter("aRegularValue");
        ParameterDAO.add(parameterWithRegularValue);

        Map device5openbsdParameterValues = new HashMap();
        device5openbsdParameterValues.put(parameterWithNullValue, null); // Only parameter value that is null.
        device5openbsdParameterValues.put(parameterWithRegularValue, "myValue");

        device5.setParameterValues(device5openbsdParameterValues);
        DeviceDAO.add(device5);
        ThreadSessionManager.commitSession();
    }
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 20, 2004 11:38 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Correct, this change was intentional (and Good, I think).

You could try using a user type, or something like that if you need to stay compatible with the existing data.


Top
 Profile  
 
 Post subject: Null-values in Map: 1.x to 2.x difference
PostPosted: Tue Jan 20, 2004 11:48 am 
Newbie

Joined: Tue Jan 20, 2004 10:27 am
Posts: 2
Hi Gavin,

Thanks for your quick response.

We will probably be able to work around the current situation: either with a user type as you mentioned or (more likely) with making some changes in the business part of the application. A user type sounds not trivial in this case as it's a Map.

Still, I'm curious: why was this decision made? Is it difficult to implement null-value in such a Map? And if it is explicitely not allowed, why not throw an appropriate Exception instead?

From java.util.Map:
Quote:
Some map implementations have restrictions on the keys and values they may contain. For example, some implementations prohibit null keys and values, and some have restrictions on the types of their keys. Attempting to insert an ineligible key or value throws an unchecked exception, typically NullPointerException or ClassCastException.


Kind regards,
Guus


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 03, 2004 6:39 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
I would also like an explanation why it is good the map cannot contain null element values. It's kind of disturbing to have seemingly working program and find out that not all data is beeing inserted. At least an exception should be thrown and explaing that the entity cannot be saved!


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 25, 2004 5:10 pm 
Beginner
Beginner

Joined: Wed Dec 03, 2003 2:43 pm
Posts: 22
Hi,

I was wondering if there was any more information on this. I too have a data model, where the map values must be nullable. Is there a default workaround? Is the UserType suggested simply one that returns the type of the given value but allows nulls? (i.e. if it is a String it returns a String etc) where the element of the Map is this UserType or is it more complicated than that?

Thanks,
Gabe


Top
 Profile  
 
 Post subject: Would this work?
PostPosted: Thu May 27, 2004 12:01 pm 
Beginner
Beginner

Joined: Wed Dec 03, 2003 2:43 pm
Posts: 22
I am wondering if this would work: Instead of a UserType use a composite-element with one column.

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
   
<hibernate-mapping>
  <class name="nl.chess.hibernateupgrade.model.Device"
  table="rmgt_device">
    <id name="dbId" type="long">           
         <generator class = "native">           
         </generator>       
      </id>

    <property name="name" not-null="true" />

    <map name="parameterValues" cascade="save-update"
    table="rmgt_parametervalues">
      <key column="id_device_element" />

      <index-many-to-many column="id_parameter"
      class="nl.chess.hibernateupgrade.model.Parameter" />

      <composite-element class="nl.chess.hibernateupgrade.model.DeviceMapValue">
            <property name="value" column="value" type="string" not-null="false"/>
       </composite-element>
    </map>
  </class>
</hibernate-mapping>


Then just set the value of the composite element class to null.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 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.