您的位置:首页 > 其它

Hibernate中criteria一对多关联查询时distinct的分页和数量问题

2017-04-28 01:01 274 查看
吐个槽:

hibernate Criteria 为何不能在结果集返回前就筛出重复,还不能分组,不能 DISTINCT, 否则返回单数据, 希望高手指点。

解决办法: 

原文: 

数据模型

班级:clazz(id,name,studentList)

学生:student(id,name,address,clazz)

经典查询

查询有地址在成都的班级信息,并分页显示。

一般情况下,以上的条件更多,也更复杂,且查询主体必须从班级入手。那么,使用Hibernate的criteria查询的话,一般情况下,编码如下:

单就逻辑本身,看似没有什么问题,且在数据较少(如没有分页数据时),会返回正确的结果。但是一旦出现分页数据时,你就会发现,分页数据是错的。表现结果为page对象所表现的数据总数明确不对,且每页所显示的数据也并不是分页信息中的20条,而是不确定的几条(明显少于默认的20条)。这就表明,在这个查询中,肯定有一步出问题了。

没错,在这个查询中,我们要求返回的主体为班级,即Clazz。但Hibernate出生的sql却并不能如我们所愿,它直接使用连接来组装sql语句,并尝试返回包括学生在类的一个复合对象,然后再组装成班级对象,最后根据集合信息进行distinct操作,最后就形成了不正确的结果。整个操作看起来如下所示:

看到以上的过程,你大概知道什么问题了吧。所使用setResultTransformer(distinct)并没有反映到所生成的sql中,而却是在取得结果后再进行。

此问题在:http://stackoverflow.com/questions/300491/how-to-get-distinct-results-in-hibernate-with-joins-and-row-based-limiting-pagi 也有提及。即如何在关联查询时返回distinct的主体信息。

有人会说,那就在criteria中加入类似distinct的查询条件,或者只让hibernate查询a.*吧。值得抱歉的是,值到现在hibernate并没有提供这样的功能。那么如何解决这个问题呢,在所引用的英文提问中,提到一种方式,就是使用 setProjection(Projections.distinctProperty(id))先把a的id查询出来。详细逻辑如下所示:

总共需要查询3次查询,第一步查总数,第二步查询结果所对应的主键id,第三步使用id再查询具体的对象信息。对于比较复杂的查询来说,这三步必不可少。然而对于像本方比较简单的查询,可以使用exists来代替innerJoin关联查询,这种方式可以避免在查询语句中查询出b.*。

通过这种将关联查询转化为exists子查询,可以确保在生成的select sql语句中,只会查询a.*。这就减少了查询结果,同时也满足我们所需要的结果。

如果是简单的条件查询,使用hql肯定会更简单,同时也能够控制所生成的sql语句。当只能使用criteria进行构建查询时,为保证结果的正确性,尽量使用exists式的子查询,可以保证查询对象的尽量少,也可以保证结果的正确性。特别是当需要从一方关联多的一方进行关联查询时,尤其需要注意返回结果的正确性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: