Hibernate Version:2.1.2
MyObject Mapping:
Code:
<hibernate-mapping>
<class name="com.company.package.MyObject" table="MyObjects">
<id name="id" column="ObjectID" type="string">
<generator class="assigned"/>
</id>
<set name="properties" table="ObjectProperties" cascade="all">
<key column="ObjectID"/>
<many-to-many class="com.company.package.Property" column="PropertyID"/>
</set>
</class>
</hibernate-mapping>
Property Mapping:
Code:
<hibernate-mapping>
<class name="com.company.package.Property" table="Properties">
<id name="PropertyId" column="PropertyID" type="string">
<generator class="assigned"/>
</id>
<map name="Map" table="PropertyMaps" cascade="all">
<key column="PropertyID"/>
<index-many-to-many class="com.company.package.MapName" column="MapNameID"/>
<many-to-many class="com.company.package.MapValue" column="MapValueID"/>
</map>
</class>
</hibernate-mapping>
MapName Mapping:
Code:
<hibernate-mapping>
<class name="com.company.package.MapName" table="MapNames">
<id name="id" column="MapNameID" type="string">
<generator class="assigned"/>
</id>
</class>
</hibernate-mapping>
MapValue Mapping:
Code:
<hibernate-mapping>
<class name="com.company.package.MapName" table="MapValues">
<id name="id" column="MapValueID" type="string">
<generator class="assigned"/>
</id>
</class>
</hibernate-mapping>
Java Code:
Code:
MyObject o = new MyObject('123');
Property prop1 = new Property('456');
Map map1 = new Map('789');
map1.put(new MapName('name1'), new MapValue('val'));
prop1.setMap(map1);
o.addProperty(prop1);
Property prop2 = new Property('def');
Map map2 = new Map('ghi');
map2.put(new MapName('name2'), new MapValue('val'));
prop2.setMap(map2);
o.addProperty(prop2);
session.replicate(o, ReplicationMode.OVERWRITE);
Hibernate says it's doing the following (I've taken the liberty of manually hydrating the log entries for clarity):
Code:
Hibernate: select MyObjectID from MyObjects where MyObjectID = '123'
Hibernate: select PropertyID from Properties where PropertyID = '456'
Hibernate: select MapValueID from MapValues where MapValueID = 'val'
Hibernate: select PropertyID from Properties where PropertyID = 'def'
Hibernate: select MapValueID from MapValues where MapValueID = 'val'
Hibernate: insert into MyObjects (ObjectID) values ('123')
Hibernate: insert into Properties (PropertyID) values ('456')
Hibernate: insert into MapValues (MapValueID) values ('val')
Hibernate: insert into Properties (PropertyID) values ('def')
Hibernate: insert into MapValues (MapValueID) values ('val')
Exception Thrown:
com.jnetdirect.jsql.x: Violation of PRIMARY KEY constraint 'PK__MapValues__6DCC4D03'. Cannot insert duplicate key in object 'MapValues'.
Seems like Hibernate assumes that no two object instances with the same id will be committed to the database in the same transaction. Does this exception occur when persisting any map that contains two keys with the same value (same primary key)? This has only presented as a problem because we have to use a special MapValue instance to represent a null value (Hibernate will not persist a Map entry with null value). Since each of these special null object instances have the same id and the MapObject may contain several of them at the same time the exception presents itself. I suppose it could be an enhancement request to allow null values in Maps, but I see in JIRA that idea has already been discarded. Another possiblity might be to discard all but one of the duplicate insert statements during commit. Or maybe there is another strategy that I can use to acheive the same functionality?
It may be worth noting that all objects implement equals() and hashCode() around their respective id fields.
Any suggestions or work arounds are greatly appreciated!
Thanks! Keep up the great work Hibernate Team, we love your project!
-Alex