Hi,
I've been struggling with getting bidirectional list associations working and am now wondering if they are even possible. My copy of hibernate in action (probably out of date) says that such an association is not possible but this page on the hibernate site says that it is supported in hibernate3
http://www.hibernate.org/193.html
Anyway, I've created a small test case to show my problem. It's the familiar parent/child relationship but I've changed the child to be a List rather than a Set to show the problem. Here is the java class, mapping document and test case.
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="test">
<class name="Person">
<id name="id">
<generator class="increment"/>
</id>
<many-to-one name="parent" class="Person" cascade="all" />
<list name="children" cascade="all" inverse="true">
<key column="parent"/>
<list-index column="list_index"/>
<one-to-many class="Person"/>
</list>
</class>
</hibernate-mapping>
Code:
package test;
import java.util.*;
public class Person
{
private Integer id;
private Person parent;
private List<Person> children = new ArrayList<Person>();
public void setId(Integer anId)
{
id = anId;
}
public Integer getId()
{
return id;
}
public Person getParent()
{
return parent;
}
public void setParent(Person anParent)
{
parent = anParent;
}
public List<Person> getChildren()
{
return children;
}
public void setChildren(List<Person> anChildren)
{
children = anChildren;
}
}
Code:
public void testSavePerson() throws Exception
{
Session _session = sessionFactory.openSession();
_session.beginTransaction();
Person _parent = new Person();
Person _child1 = new Person();
_parent.getChildren().add(_child1);
_child1.setParent(_parent);
_session.save(_parent);
_session.getTransaction().commit();
_session.close();
_session = sessionFactory.openSession();
Person _readBack = (Person) _session.get(Person.class, _parent.getId());
assertEquals(1, _readBack.getChildren().size());
_session.close();
}
When I run the test an Exception is thrown when I call _readBack.getChildren()
Code:
org.hibernate.HibernateException: null index column for collection: test.Person.children
at org.hibernate.persister.collection.AbstractCollectionPersister.readIndex(AbstractCollectionPersister.java:710)
at org.hibernate.collection.PersistentList.readFrom(PersistentList.java:379)
at org.hibernate.loader.Loader.readCollectionElement(Loader.java:1008)
at org.hibernate.loader.Loader.readCollectionElements(Loader.java:646)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:591)
at org.hibernate.loader.Loader.doQuery(Loader.java:701)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.loadCollection(Loader.java:1994)
at org.hibernate.loader.collection.BatchingCollectionInitializer.initialize(BatchingCollectionInitializer.java:52)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:565)
at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:60)
at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1716)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:344)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:109)
at org.hibernate.collection.PersistentList.size(PersistentList.java:91)
at test.TestCasePerson.testSavePerson(TestCasePerson.java:27)
SchemaExport creates the table as
Code:
create table person (
id integer not null,
parent integer,
list_index integer,
primary key (id)
) type=InnoDB
The sql log is
Code:
Hibernate: select max(id) from person
Hibernate: insert into person (parent, id) values (?, ?)
Hibernate: insert into person (parent, id) values (?, ?)
Hibernate: select person0_.id as id12_0_, person0_.parent as parent12_0_ from person person0_ where person0_.id=?
Hibernate: select children0_.parent as parent1_, children0_.id as id1_, children0_.list_index as list3_1_, children0_.id as id12_0_, children0_.parent as parent12_0_ from person children0_ where children0_.parent=?
The mapping looks right but I can't see how to make hibernate use the <list-index> parameter from the inverse side of the relationship. In a way this makes sense as the inverse side of the relationship is ignored, so do I need to somehow add a <list-index> to the <many-to-one> side of the association?
If I change the association to a Set it works as expected. Also if I make the association unidirectional (remove the inverse="true" and the <many-to-one> mapping) it works.
So any ideas where I am going wrong, is this even possible? I'm using hibernate 3.2.5 and have tested on both MySQL 5 & HSQLDB.
Many thanks,
Matt