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.xmlCode:
<?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.xmlCode:
<?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 testcaseCode:
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();
}
}