如何将通用Blaze Persistence查询包装为子查询以按ROW_NUMBER()=1筛选?
如何将通用Blaze Persistence查询包装为子查询以按ROW_NUMBER()=1筛选?
我明白你的痛点——在泛型场景下手动绑定实体属性完全不可行,fromEntitySubquery确实是解决这个问题的正确方向,只是它的用法需要稍微调整一下。你之前的尝试把内部查询的逻辑结构放错了位置,下面是正确的实现方式:
return criteriaBuilder // 1. 外层查询:基于实体子查询构建,自动映射传入的entityClass类型 .fromEntitySubquery(entityClass, "groupedEntity") // 2. 定义子查询(对应原有的完整查询逻辑) .from(entityClass, "entityData") .innerJoinOn(ChangeData.class, "changes") .on("changes.id").eqExpression("entityData.id") .end() .select("entityData") // 保留原实体数据的投影 .select("ROW_NUMBER() OVER (PARTITION BY changes.id ORDER BY changes.sequence DESC)", "rn") .select("changes.id", "changes_id") .select("changes.sequence") .selectNew(entityObjectBuilder) // 3. 外层查询添加过滤条件:只保留rn=1的最新版本记录 .where("rn").eq(1) // 4. 选择外层的实体结果,无需手动绑定属性 .select("groupedEntity") // 若需要子查询中的其他投影字段,直接引用别名即可 .select("groupedEntity.changes_id") .select("groupedEntity.sequence") .getQuery();
关键逻辑说明:
fromEntitySubquery的核心价值就是自动将子查询中的实体投影映射到外层的实体别名,完全不需要手动绑定实体的任何属性,完美适配你需要的泛型场景。- 你之前的错误是把外层的过滤条件写在了子查询内部,正确的流程是:先在子查询中计算出
rn字段,再在外层查询中通过where("rn").eq(1)筛选出每个changes.id对应的最新版本记录。 - 外层查询可以直接引用子查询中定义的所有别名(包括自定义的
rn、changes_id等),操作方式和普通实体查询完全一致。
如果你的需求只是获取每个分组下的最新实体数据,还可以简化成更简洁的版本:
return criteriaBuilder .fromEntitySubquery(entityClass, "groupedEntity") .from(entityClass, "entityData") .innerJoinOn(ChangeData.class, "changes") .on("changes.id").eqExpression("entityData.id") .end() .select("entityData") .select("ROW_NUMBER() OVER (PARTITION BY changes.id ORDER BY changes.sequence DESC)", "rn") .where("rn").eq(1) .select("groupedEntity") .getQuery();
备注:内容来源于stack exchange,提问作者fishi
相关产品推荐
相关产品推荐

