Recently Vanessa and I ran into some trouble while trying to navigate a many-to-many relationship using the Hibernate’s Criteria api. We wanted to go from one end of the relationship to the other end through the class representing the association table. This particular association table used a composite key. Here is what part of the mapping file for our association table looked like:
<hibernate-mapping> <class name="PatientPrescriber" table="patient_prescriber"> <composite-id> <key-many-to-one name="patient" column="paaa_id" /> <key-many-to-one name="prescriber" column="praa_id"/> </composite-id> </class> </hibernate-mapping>
Using the Criteria api we first created a criteria for the association class:
Criteria patientPrescriberCriteria = patientCriteria.createCriteria(?patientPrescriber?);
The next step was to use this to create a Criteria object for the class we were actually interested in:
Criteria prescriberCriteria = patientPrescriberCritera.createCriteria(?prescriber?);
Much to our frustration this ‘simple’ solution wouldn’t work and we spent much of that day pulling our hair out trying to figure out why. Eventually Vanessa and Laurence tracked down the problem to a bug in Hibernate described here. They are kind enough to state the following:
The <key-many-to-one> mapping has some minor limitations in current versions of Hibernate. — Source
The solution is to use the <key-property> mapping holding the id of the entity of interest and an association mapped to the same column.
Our mapping file ended up looking something like this:
<hibernate-mapping> <class name="PatientPrescriber" table="patient_prescriber"> <composite-id> <key-many-to-one name="patient" column="paaa_id" /> <key-property name="prescriberId" column="praa_id"/> </composite-id> <many-to-one name="prescriber" column="praa_id" insert="false" update="false" /> </class> </hibernate-mapping>
And we were able happily navigate our relationships.