Monday 14 March 2011

Hibernate and native SQL fetching

Today it took me about 3 hours to find a problem in my code that was caused by HHH-2831. Unfortunately Hibernate documentation is vague regarding 'return-join' elements. By reading comments of bug, i realized that i'm not the only one facing the same problem and in all cases it was intuition of developers which proved to be wrong.

I'll explain briefly the essence of problem. Consider two simple hibernate class mappings and named native SQL query:

  <class name="ObjectA" table="OBJECT_A">
<id column="ID" name="id">
<generator class="native" />
</id>
<property name="title" column="TITLE" type="string" length="255" not-null="true" />
<list name="children" cascade="all-delete-orphan">
<key column="OBJECT_A_ID" not-null="true" />
<list-index column="ORDER_INDEX" base="0" />
<one-to-many class="ObjectB" />
</list>
</class>
<class name="ObjectB" table="OBJECT_B">
<id column="ID" name="id">
<generator class="native" />
</id>
<property name="title" column="TITLE" type="string" length="255" not-null="true" /> </class>
<sql-query name="getAll" read-only="true">
<return alias="a" class="com.example.ObjectA" />
<return-join alias="b" property="a.children" />
select {a.*}, {b.*}
from OBJECT_A a
inner join OBJECT_B b on b.OBJECT_A_ID = b.ID
</sql-query>

Now... what do you expect of when executing something like:

List result = session.getNamedQuery("getAll").list()

I was expecting it to be a list of objects of class ObjectA without any duplicates. Unfortunately this is not the case (like it would've been when using HQL). In fact it returns a list of Object[2] elements and with as many duplicates of ObjectA as it has children. The second object in array is ObjectB (child) object. Hence you must filter the list for duplicate elements:

        List finalResult = new ArrayList();
for (Object[] objs : result) {
ObjectA obj = (ObjectA) objs[0];
if (!finalResult.contains(obj)) {
finalResult.add(obj);
}
}

I wonder what will happen in case of another level... They cannot be filtered if those collections are not inverse, because it would automatically update the list of children (remove them).

No comments:

Post a Comment