Hi!
Within some entity class Thing, I would like to map a property like
Code:
Map<Attribute, ValueList> getAttributeMap()
using Hibernate Annotations (3.2.0.CR1) where both Attribute and ValueList are entity classes.
According to the documentation, support for a real Map<Entity, Entity> is offered and so I tried
Code:
@ManyToMany(cascade = CascadeType.ALL)
Map<Attribute, ValueList> getAttributeMap()
letting Hibernate know true map support is required by omitting the javax.persistence.MapKey (Reference Guide, p. 40).
That nearly works and leads to the following DDL statement for the join table of the map:
Code:
create table Thing_ValueList (
thing_id bigint not null,
attributeMap_id bigint not null,
key_id bigint,
primary key (thing_id, key_id),
unique (key_id)
)
The problem is the unique constraint on the key_id column. It prevents setting the same Attribute for two Thing objects...
While I consider this to be a general problem, I hoped
Code:
@ManyToMany(cascade = CascadeType.ALL)
@MapKeyManyToMany(joinColumns = @JoinColumn(unique = false))
Map<Attribute, ValueList> getAttributeMap()
would solve my problem but I was wrong.
The following hbm.xml mapping for the property in question does not produce the illegal unique constraint and works as expected:
Code:
<map name="attributeMap" cascade="all" table="Thing_ValueList">
<key column="thing_id" not-null="true" />
<map-key-many-to-many column="key_id" class="Attribute" />
<many-to-many column="attributeMap_id" class="ValueList" />
</map>
but as you probably guess, I don't want to use XML mappings anymore ;-).
To reproduce the problem, just modify the test case IndexedCollectionTest.java in the package org.hibernate.test.annotations.indexcoll by extending the method testRealMap:
Code:
public void testRealMap() throws Exception {
Session s = openSession();
Transaction tx = s.beginTransaction();
Atmosphere atm = new Atmosphere();
GasKey key = new GasKey();
key.setName( "O2" );
Gas o2 = new Gas();
o2.name = "oxygen";
atm.gases.put( "100%", o2 );
atm.gasesPerKey.put(key, o2);
s.persist( key );
s.persist( atm );
// adding another atmosphere with the SAME map key
// violates the unique constraint on the map-key-column
Atmosphere atm2 = new Atmosphere();
atm2.gases.put( "100%", o2 );
atm2.gasesPerKey.put(key, o2);
s.persist( atm2 );
s.flush();
s.clear();
atm = (Atmosphere) s.get( Atmosphere.class, atm.id );
key = (GasKey) s.get( GasKey.class, key.getName() );
assertEquals( 1, atm.gases.size() );
assertEquals( o2.name, atm.gases.get( "100%" ).name );
assertEquals( o2.name, atm.gasesPerKey.get(key).name );
tx.rollback();
s.close();
}
JDBC batching should be disabled for this test so that one actually sees the constraint exception and not the batch update exception.
I hope, someone can help. Thanks in advance!