Mar,
Thanks for your post. We’d love to use DetachedCriteria – however, as it turns out, there is some difference between that class and “attached” Criteria.
Our code using attached Criteria (as per Ananasi's suggestion):
Code:
Criteria rootCriteria = session.createCriteria(Contractor.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.setFetchMode("contractorSkillGroups", FetchMode.JOIN);
rootCriteria
.add(Restrictions.eq("id", 81L))
.add(Restrictions.eq("active", true))
.createCriteria("contractorSkillGroups", Criteria.LEFT_JOIN)
.add(Restrictions.eq("active", true));
List<Contractor> list = rootCriteria.list();
Resulting SQL:
Code:
select
this_.id as id3_2_,
this_.OPT_LOCK as OPT2_3_2_,
this_.ACTIVE as ACTIVE3_2_,
this_.DISPATCH_FILE_LOCATION as DISPATCH4_3_2_,
this_.EMAIL_CC as EMAIL5_3_2_,
this_.EMAIL_TO as EMAIL6_3_2_,
this_.END_DATE as END7_3_2_,
this_.EXTERNAL_NRC_ID as EXTERNAL8_3_2_,
this_.EXTERNAL_SUPERVISOR_ID as EXTERNAL9_3_2_,
this_.FAST_TRACK_CAPACITY_VAR as FAST10_3_2_,
this_.NAME as NAME3_2_,
this_.START_DATE as START12_3_2_,
contractor1_.CONTRACTOR_ID as CONTRACTOR7_4_,
contractor1_.id as id4_,
contractor1_.id as id4_0_,
contractor1_.OPT_LOCK as OPT2_4_0_,
contractor1_.ACTIVE as ACTIVE4_0_,
contractor1_.CONTRACTOR_ID as CONTRACTOR7_4_0_,
contractor1_.DAILY_STANDARD_CAPACITY as DAILY4_4_0_,
contractor1_.FAST_TRACK_ALLOWED as FAST5_4_0_,
contractor1_.SKILL_GROUP_ID as SKILL6_4_0_,
skillgroup4_.id as id12_1_,
skillgroup4_.OPT_LOCK as OPT2_12_1_,
skillgroup4_.DISPATCH_AREA_ID as DISPATCH3_12_1_,
skillgroup4_.SKILL_TYPE_ID as SKILL4_12_1_
from
CONTRACTOR this_,
CONTRACTOR_SKILL_GROUP contractor1_,
SKILL_GROUP skillgroup4_
where
this_.id=contractor1_.CONTRACTOR_ID(+)
and contractor1_.SKILL_GROUP_ID=skillgroup4_.id(+)
and this_.id=?
and this_.ACTIVE=?
and contractor1_.ACTIVE=?
Note the two outer joins above.
Code using DetachedCriteria:
Code:
DetachedCriteria rootCriteria = DetachedCriteria.forClass(Contractor.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.setFetchMode("contractorSkillGroups", FetchMode.JOIN)
.setFetchMode("contractorSkillGroups.skillGroup", FetchMode.JOIN)
;
rootCriteria
.add(Restrictions.eq("id", 81L))
.add(Restrictions.eq("active", true))
.createCriteria("contractorSkillGroups")
.add(Restrictions.eq("active", true))
;
Note I wasn't entirely sure where to stick setFetchMode statements, so I put them in the very beginning (if you've got better suggestions please let us know).
Resulting SQL:
Code:
select
this_.id as id3_2_,
this_.OPT_LOCK as OPT2_3_2_,
this_.ACTIVE as ACTIVE3_2_,
this_.DISPATCH_FILE_LOCATION as DISPATCH4_3_2_,
this_.EMAIL_CC as EMAIL5_3_2_,
this_.EMAIL_TO as EMAIL6_3_2_,
this_.END_DATE as END7_3_2_,
this_.EXTERNAL_NRC_ID as EXTERNAL8_3_2_,
this_.EXTERNAL_SUPERVISOR_ID as EXTERNAL9_3_2_,
this_.FAST_TRACK_CAPACITY_VAR as FAST10_3_2_,
this_.NAME as NAME3_2_,
this_.START_DATE as START12_3_2_,
contractor1_.id as id4_0_,
contractor1_.OPT_LOCK as OPT2_4_0_,
contractor1_.ACTIVE as ACTIVE4_0_,
contractor1_.CONTRACTOR_ID as CONTRACTOR7_4_0_,
contractor1_.DAILY_STANDARD_CAPACITY as DAILY4_4_0_,
contractor1_.FAST_TRACK_ALLOWED as FAST5_4_0_,
contractor1_.SKILL_GROUP_ID as SKILL6_4_0_,
skillgroup4_.id as id12_1_,
skillgroup4_.OPT_LOCK as OPT2_12_1_,
skillgroup4_.DISPATCH_AREA_ID as DISPATCH3_12_1_,
skillgroup4_.SKILL_TYPE_ID as SKILL4_12_1_
from
CONTRACTOR this_,
CONTRACTOR_SKILL_GROUP contractor1_,
SKILL_GROUP skillgroup4_
where
this_.id=contractor1_.CONTRACTOR_ID
and contractor1_.SKILL_GROUP_ID=skillgroup4_.id(+)
and this_.id=?
and this_.ACTIVE=?
and contractor1_.ACTIVE=?
Note that there is now an inner, rather than outer join between CONTRACTOR and CONTRACTOR_SKILL_GROUP.
I'm only hypothesising here, but maybe the inner join between CONTRACTOR and CONTRACTOR_SKILL_GROUP prevents CONTRACTOR_SKILL_GROUP data from being loaded properly?
A significant difference between "attached" and Detached Criteria is that the former supports LEFT_JOIN
Code:
.createCriteria("contractorSkillGroups", Criteria.LEFT_JOIN)
while the latter doesn't.
Nevertheless, when I set FetchType.EAGER for Contractor.contractorSkillGroups, the thing works fine even with the DetachedCriteria. Not sure whether we should enable eager fetching on that association as there are about 200 CONTRACTOR_SKILL_GROUP records per each CONTRACTOR, so the performance hit may be rather significant (I guess caching may help here but it has its own downsides).
Cheers,
A.