I'm having a problem with Hibernate's Criteria API. For unknown reason adding a left-join type alias changes the resultset.
I want to recreate the following SQL query in Criteria API:
select distinct f.*
from form_instance i
join form_value v on v.form_instance_id = i.id
join form_field f on f.form_field_id = v.form_field_id
where
(f.id = ? and v.value = ?)
or (f.id = ? and v.value = ?)
The mapping (only relevant fields) comes from legacy code (I haven't worked with xml mapping in hibernate nor composite ids).
FormInstance:
(I've tried disabling lazy loading, no effect)
<set name="values" lazy="true" batch-size="200" cascade="all,delete-orphan" inverse="true">
<key column="form_instance_id"/>
<one-to-many class="FormValue" not-found="ignore" />
</set>
FormValue:
<composite-id>
<key-many-to-one name="field"
column="form_field_id"
class="com.sales.model.FormField" />
<key-many-to-one name="formInstance" column="form_instance_id" />
<key-property column="value_index" name="valueIndex" />
</composite-id>
FormField:
<many-to-one class="com.sales.model.FormField"
column="parent_field_id" insert="false"
name="parentField" not-null="false" update="false"/>
I won't go into details about how exactly criteria are constructed, since It's not critical. Detached criteria is created for FormInstabnce.class
and then some minor restrictions are added.
When I execute hibernateTemplate.findByCriteria(detachedCriteria, 1, 10)
I get only 1 result, although when I try to count distinct root entities, the result is correct (2000+ results)
criteria.setProjection(Projections.countDistinct(rootEntityId));
Long result = (Long) dataObjectDAO.findByCriteria(criteria, 1).get(0);
(after this operation I reset projection and resultTransformer obvio
criteria.setProjection(null);
criteria.setResultTransformer(CRITERIA_RESULT_TRANSFORMER);
I've tried debugging this and the problem arises (changed result count) when I add alias to formValue:
detachedCriteria.createAlias("values", "values", CriteriaSpecification.LEFT_JOIN);
During debugging, I've dumped the queries that are executed and there is difference when I add the alias - this might hint someone more proficient in Hibernate to what's actually going on. I've replaced field lists with * to improve readability.
Without alias, correct result:
select * from (
select *
from bank.form_instance this_
where this_.product=?
order by this_.pf_date desc
)
where rownum <= ?
With alias, incorrect result (1 row):
select * from (
select *
from bank.form_instance this_
left outer join bank.form_value values1_ on this_.id=values1_.form_instance_id
where this_.product=? and ((this_.user_name=?)) order by this_.pf_date desc
)
where rownum <= ?
select *
from bank.form_field formfield0_
where formfield0_.form_field_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
I've tried going deeper with debugging, but when I tried debugging on decompiled Hibernate classes my IDE desynchronized and it turned out impossible without additional work.
What is interesting is that the 2nd query searches only for 10 formFields, although there's like 180 formFields for every formInstance, and 10 is the value that's passed to searchByCriteria method.
I suspect that hibernate mapping is incorrect, but I'm not proficient enought to find out by myself. Any help would be deeply appreciated, I'm stuck on this problem for 2 days now and I'm getting really frustrated.
Best regards, Jony