Blaze Persistence集成QueryDSL:Join子查询结合CTE投影报错求助
问题:Blaze Persistence + QueryDSL 中CTE结合Join子查询报错
现有Person和Pet两个实体,结构如下:
| Person | Pet |
|---|---|
| id | id |
| name | personId |
| age |
测试代码尝试通过CTE统计宠物年龄总和,关联Person并筛选总和超过30的记录:
blazeJPAQueryFactory.selectFrom(QPerson.person) .leftJoin( JPQLNextExpressions .select(Projections.bean( PersonPetCte.class, QPet.pet.personId.as(QPersonPetCte.personPetCte.personId), QPet.pet.age.sum().as(QPersonPetCte.personPetCte.ageSum) )) .from(QPet.pet) .groupBy(QPet.pet.personId), QPersonPetCte.personPetCte ) .on(QPersonPetCte.personPetCte.personId.eq(QPerson.person.id)) .where(QPersonPetCte.personPetCte.ageSum.gt(30)) .fetch();
CTE实体定义:
@CTE @Entity public class PersonPetCte { @Id Long personId; Long ageSum; // 省略getter/setter }
运行后抛出异常:
java.lang.UnsupportedOperationException: Select statement should be bound to any CTE attribute
需求:获取所有宠物年龄总和超过30的Person,希望避免硬编码字符串,采用CTE实现。
解决方案
核心问题是把CTE当成普通子查询直接Join,Blaze Persistence中CTE的使用需要先通过with方法声明绑定,而非直接在Join里嵌套子查询投影到CTE实体。
正确写法需先通过with定义CTE,再关联查询:
blazeJPAQueryFactory.with(QPersonPetCte.personPetCte) .as( JPQLNextExpressions.select( Projections.bean( PersonPetCte.class, QPet.pet.personId.as(QPersonPetCte.personPetCte.personId), QPet.pet.age.sum().as(QPersonPetCte.personPetCte.ageSum) ) ) .from(QPet.pet) .groupBy(QPet.pet.personId) ) .selectFrom(QPerson.person) .innerJoin(QPersonPetCte.personPetCte) .on(QPersonPetCte.personPetCte.personId.eq(QPerson.person.id)) .where(QPersonPetCte.personPetCte.ageSum.gt(30)) .fetch();
关键说明:
- CTE必须先声明:使用
with(CTE实体QueryDSL对象).as(子查询)的方式,先将CTE的数据源绑定到CTE实体上,这是Blaze Persistence处理CTE的标准流程,也是解决该异常的核心。 - 关联方式调整:声明CTE后,直接关联CTE的QueryDSL对象即可,无需再在Join里嵌套子查询。
- 改用InnerJoin更合理:需求是筛选宠物年龄总和超30的Person,InnerJoin可自动过滤无符合条件宠物的Person,比LeftJoin后加Where更高效。
该写法既避免了硬编码字符串,又符合Blaze Persistence对CTE的使用规范,能正确执行查询。
内容的提问来源于stack exchange,提问作者pterogum
相关产品推荐
相关产品推荐

