Hibernate native SQL query - how to get distinct root entities with eagerly initialized one-to-many association

流过昼夜 提交于 2021-02-11 14:27:04

问题


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 Depts, 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 Emps of all Depts.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!