JPA CriteriaQuery如何添加Join关联查询并附加字段过滤条件
问题根因
你遇到的Cannot join to attribute of basic type报错,本质是JPA Criteria API的join方法只能作用于实体类的关联属性,不能直接作用于普通的基本类型外键字段。你之前尝试join的id是FlowStep自身的主键(基础UUID类型),不属于关联实体属性,因此触发报错。
你要实现的关联查询有两种实现方案:
方案一:配置实体关联关系(推荐)
你理解的方向是正确的,由于一个FlowInstance对应多个FlowStep,属于一对多关联,你需要把FlowStep中原来的基础类型外键字段替换为@ManyToOne关联配置:
// 删除原有的flowInstanceId字段定义 // @Column(name = flowinstanceid) // private UUID flowInstanceId; // 替换为多对一关联配置 @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "flowinstanceid", referencedColumnName = "id") private FlowInstance flowInstance;
如果需要可以在FlowInstance类中补充反向的@OneToMany配置,不补充也不影响本次查询逻辑。
修改完实体后,你的查询代码调整如下即可:
CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<FlowStep> cbQuery = cb.createQuery(FlowStep.class); Root<FlowStep> flowStep = cbQuery.from(FlowStep.class); List<Predicate> predicates = new ArrayList<>(); // 新增关联逻辑 Join<FlowStep, FlowInstance> flowInstanceJoin = flowStep.join("flowInstance", JoinType.INNER); predicates.add(cb.equal(flowInstanceJoin.get("domainid"), "Test")); // 原有其他谓词、排序逻辑全部保留即可 // ... cbQuery.select(flowStep).where(predicates.toArray(new Predicate[0])).orderBy(orders); Query query = em.createQuery(cbQuery); List<FlowStep> resultList = query.getResultList();
该方案生成的SQL完全符合你预期的关联查询逻辑,且符合JPA规范,后续其他关联查询也可以复用该关联配置。
方案二:不改实体用隐式关联实现
如果你暂时不想修改现有实体配置,也可以通过多Root查询的方式实现同样效果,无需使用join方法:
CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<FlowStep> cbQuery = cb.createQuery(FlowStep.class); Root<FlowStep> flowStep = cbQuery.from(FlowStep.class); // 新增FlowInstance的查询根 Root<FlowInstance> flowInstance = cbQuery.from(FlowInstance.class); List<Predicate> predicates = new ArrayList<>(); // 手动关联外键,等价于join逻辑 predicates.add(cb.equal(flowStep.get("flowInstanceId"), flowInstance.get("id"))); // 加domainid过滤条件 predicates.add(cb.equal(flowInstance.get("domainid"), "Test")); // 原有其他谓词、排序逻辑全部保留即可 // ... cbQuery.select(flowStep).where(predicates.toArray(new Predicate[0])).orderBy(orders); Query query = em.createQuery(cbQuery); List<FlowStep> resultList = query.getResultList();
该方案生成的SQL和你预期的关联查询效果完全一致,属于SQL层面的隐式内连接。
内容的提问来源于stack exchange,提问作者Pavitx
相关产品推荐
相关产品推荐

