问题
I have two entities Dept
and Emp
(real case changed and minimized). There is 1:n association between them, i.e. properties Dept.empList
and Emp.dept
exist with respective annotations. I want to get List<Dept>
whose elements are distinct and have collection empList
eagerly initialized, using native SQL query.
session.createSQLQuery("select {d.*}, {e.*} from dept d join emp e on d.id = e.dept_id")
.addEntity("d", Dept.class)
.addJoin("e", "d.empList")
//.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
This query returns List<Object[2]>
with instances of Dept
, Emp
(in that order) in the array and field Dept.empList
properly initialized. That's ok.
To get distinct Dept
s, I thought setting transformer DISTINCT_ROOT_ENTITY
(uncommenting the line) would be enough. Unfortunately, the DistinctRootEntityResultTransformer
is based on RootEntityResultTransformer
which treats the last element in tuple as root entity (it's hardwired). Since the order of entities is determined by sequence of addEntity
, addJoin
calls, the transformer mistakenly treats Emp
as root entity and returns list with all Emp
s of all Dept
s.
Is there any clean way how to make Hibernate recognized the Dept
as root entity, even though it is not last in entity list?
Note 1: I tried to switch order to .addJoin("e", "d.empList").addEntity("d", Dept.class)
. Does not work since d.empList
requires d
defined. Fails on HibernateSystemException : Could not determine fetch owner
somewhere in Hibernate internals (org.hibernate.loader.Loader
).
Note 2: I tried to define order as .addEntity("e", Emp.class).addJoin("d", "e.dept")
. This seemingly works but the association is actually filled only from the "many" side. Hence the collection Dept.empList
is some uninitialized proxy until requested, which invokes explicit SQL query and thus does not utilize the join in my query.
Note 3: The custom transformer looking for hard-wired index works:
.setResultTransformer(new BasicTransformerAdapter() {
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple[0];
}
public List transformList(List list) {
return DistinctResultTransformer.INSTANCE.transformList( list );
}
})
though I'm hesitant to accept such easy task could have such complicated solution.
Hibernate version: 3.6.10 (I know - legacy project :-) though I looked into source code of latest version and seems the key points don't differ).
回答1:
Finally found https://stackoverflow.com/a/17210746/653539 - make duplicate call of .addEntity
to force root entity on the end of list:
.addEntity("d", Dept.class)
.addJoin("e", "d.empList")
.addEntity("d", Dept.class)
It's still workaround but cleaner than mine and - based on 36 upvotes - it seems as idiomatic solution.
来源:https://stackoverflow.com/questions/62554257/hibernate-native-sql-query-how-to-get-distinct-root-entities-with-eagerly-init