JPA CriteriaQuery复用Select表达式到OrderBy的问题(Hibernate 6.2.6)
使用Hibernate 6.2.6 CriteriaAPI实现左连接排序时的OrderBy异常问题
目标SQL
select foo.id, foo.bar, bar.name from foo left join bar on bar.code = foo.bar order by bar.name;
我的Kotlin实现代码
val builder = em.criteriaBuilder val query = builder.createQuery(Any::class.java) val root = query.from(Foo::class.java) val sortJoin = root.join<Foo, Bar>("bar", JoinType.LEFT).get<Expression<*>>("name") query.multiselect(root, sortJoin) query.orderBy(builder.asc(sortJoin))
问题现象
Hibernate生成的SQL中OrderBy子句被错误替换为常量20:
select s1_0.id, s1_0.bar, s2_0.name from foo s1_0 left join bar s2_0 on s2_0.code=s1_0.bar order by 20
YDB要求排序字段必须出现在Select列表中,但如果不在multiselect中加入bar.name,OrderBy子句正常;尝试使用别名、分开定义表达式均无效,分开定义还会生成重复Join。
临时方案:将整个Join对象放入multiselect可正常生成排序,但会查询出多余字段,需要更优的表达式复用方案。
最优解决方案
通过明确拆分查询字段、复用同一个表达式来解决问题,避免直接传入root导致的关联识别错误:
val builder = em.criteriaBuilder val query = builder.createQuery(Any::class.java) val root = query.from(Foo::class.java) // 定义左连接对象,后续复用 val barJoin = root.join<Foo, Bar>("bar", JoinType.LEFT) // 单独定义每个需要查询的字段表达式 val fooId = root.get<Long>("id") val fooBarColumn = root.get<String>("bar") val barName = barJoin.get<String>("name") // 明确指定要查询的字段,避免传入root带来的歧义 query.multiselect(fooId, fooBarColumn, barName) // 直接复用barName表达式排序 query.orderBy(builder.asc(barName))
原理说明
直接传入root到multiselect时,Hibernate无法正确将排序用的bar.name表达式与Select列表中的对应字段关联,导致生成错误的排序位置索引。拆分每个查询字段并复用同一个barName表达式后,Hibernate能准确识别排序字段对应的Select项,生成正确的OrderBy子句,同时避免重复Join和多余字段查询。
内容的提问来源于stack exchange,提问作者dtadescu
相关产品推荐
相关产品推荐

