我有这个测试HQL:
select distinct o from Order o left join fetch o.lineItems
并且它确实生成了一个SQL别而没有明显的原因:
select distinct order0_.id as id61_0_, orderline1_.order_id as order1_62_1_...
SQL结果集总是相同的(有和没有SQL不同):
order id | order name | orderline id | orderline name
---------+------------+--------------+---------------
1 | foo | 1 | foo item
1 | foo | 2 | bar item
1 | foo | 3 | test item
2 | empty | NULL | NULL
3 | bar | 4 | qwerty item
3 | bar | 5 | asdfgh item
为什么hibernate生成SQL不同? SQL distinct没有任何意义,使得查询比需要的慢 . 这与FAQ相反,后者提到在这种情况下hql distinct只是结果转换器的快捷方式:
session.createQuery(“从Order o left join fetch o.lineItems中选择不同的o”) . list();看起来您在这里使用SQL DISTINCT关键字 . 当然,这不是SQL,这是HQL . 在这种情况下,这个不同只是结果转换器的快捷方式 . 是的,在其他情况下,HQL distinct将直接转换为SQL DISTINCT . 不是在这种情况下:您无法在SQL级别过滤掉重复项,产品/连接的本质禁止这样做 - 您需要重复项或者您没有获得所需的所有数据 .
谢谢
2 回答
仔细看看hibernate生成的sql语句 - 是的它确实使用了“distinct”关键字但不是我认为你期望它的方式(或者Hibernate FAQ暗示的方式),即返回一组“不同的”或“独特的”订单 .
它不使用distinct关键字来返回不同的顺序,因为考虑到您指定的连接,在SQL查询中没有意义 .
生成的sql集仍然需要由ResultTransformer处理,因为sql set显然包含重复的订单 . 这就是为什么他们说HQL distinct关键字不直接映射到SQL distinct关键字 .
我有完全相同的问题,我认为这是一个Hibernate问题(不是一个错误,因为代码不会失败) . 但是,我必须深入挖掘以确保它是一个问题 .
Hibernate(至少在版本4中,它是我正在处理我的项目的版本,特别是4.3.11)使用SPI的概念,长话短说:它就像一个扩展或修改框架的API .
我利用这个功能来替换类
org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory
(这个类由Hibernate调用并委托生成SQL查询的工作)和org.hibernate.hql.internal.ast.QueryTranslatorImpl
(这是一种内部类,由org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory
调用并生成实际的SQL查询) . 我做了如下:更换
org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory
:更换
org.hibernate.hql.internal.ast.QueryTranslatorImpl
:如果您遵循代码流程,您会注意到我刚刚修改了方法
private void generate(AST sqlAst) throws QueryException, RecognitionException
并添加了以下行:我对此代码的处理方法是从生成的SQL查询中删除distinct关键字 .
在创建上面的类之后,我在hibernate配置文件中添加了以下行:
这一行告诉hibernate使用我的自定义类来解析HQL查询并生成没有distinct关键字的SQL查询 . 请注意,我在原始HQL解析器所在的同一个包中创建了自定义类 .