如何在QueryDSL的LEFT JOIN中使用子查询关联OneToMany属性?
解决方案
针对QueryDSL/JPA中LEFT JOIN OneToMany关联时需要使用子查询的场景,结合你已引入的Blaze Persistence,可以通过以下两种方式实现:
方式一:自定义JOIN关联条件(含子查询)
Blaze Persistence扩展了QueryDSL的JOIN能力,允许通过.on()方法添加自定义关联条件,包括嵌套子查询。如果你的需求是仅关联符合特定子查询过滤条件的criteria,可以这样修改代码:
BlazeJPAQuery<Review> reviewJPAQuery = new BlazeJPAQuery<>(entityManager, cbf) .select(review) .from(review) .leftJoin(review.configElement, configElement).fetchJoin() .leftJoin(configElement.node, node).fetchJoin() .leftJoin(node.project, project).fetchJoin() .leftJoin(review.milestone, milestone).fetchJoin() // 替换默认LEFT JOIN,添加自定义关联条件(支持子查询) .leftJoin(review.criteria, criterion) .on(criterion.review.id.eq(review.id) // 这里可添加子查询过滤逻辑,示例:仅关联未删除的criteria // .and(criterion.id.in(new JPASubquery<Long>() // .select(criterion.id) // .from(criterion) // .where(criterion.deleted.isFalse())) ) .fetchJoin() .where(globalReviewsFilter) .orderBy(orderSpecifiers);
方式二:关联子查询的结果集(派生表)
如果需要直接LEFT JOIN子查询生成的结果集(而非实体映射的关联),可以先构建子查询,再将其作为关联目标:
QCriterion criterion = QCriterion.criterion; // 构建子查询,定义需要关联的criteria数据 JPASubquery<Criterion> criteriaSubquery = new JPASubquery<>() .select(criterion) .from(criterion) .where(/* 这里添加子查询的过滤条件,比如criterion.score.gt(80) */); BlazeJPAQuery<Review> reviewJPAQuery = new BlazeJPAQuery<>(entityManager, cbf) .select(review) .from(review) .leftJoin(review.configElement, configElement).fetchJoin() .leftJoin(configElement.node, node).fetchJoin() .leftJoin(node.project, project).fetchJoin() .leftJoin(review.milestone, milestone).fetchJoin() // LEFT JOIN子查询结果,指定关联条件 .leftJoin(criteriaSubquery, criterion) .on(criterion.review.id.eq(review.id)) .fetchJoin() .where(globalReviewsFilter) .orderBy(orderSpecifiers);
注意事项
- 若仅需默认关联条件(
review.id = criterion.review.id),原代码异常可能并非来自JOIN逻辑,需排查是否因多fetchJoin导致笛卡尔积、实体映射错误或查询结果重复问题,此时可考虑移除fetchJoin改用EntityGraph控制关联加载。 - Blaze Persistence的JOIN扩展完全兼容QueryDSL语法,无需调整原有查询的其他部分。
内容的提问来源于stack exchange,提问作者bullgr
相关产品推荐
相关产品推荐

