如何正确在JPA Criteria API中使用JOIN?关联查询构造函数报错如何解决
问题原因
核心错误来自criteriaQuery.multiselect(join)这行代码:
- 你已经通过
criteriaBuilder.createQuery(ReceivedFax.class)指定了查询返回类型为ReceivedFax,默认会查询Root对象(也就是ReceivedFax)的所有属性,不需要手动指定select规则 - 你传入join对象(对应
Account实体)作为multiselect的参数后,Hibernate会尝试将查询到的Account对象作为入参构造ReceivedFax实例,而你的ReceivedFax类没有定义仅接收Account类型参数的构造函数,因此触发构造函数找不到的报错。
解决方案
- 首先删除
criteriaQuery.multiselect(join)这行冗余代码,默认就会返回符合条件的ReceivedFax完整对象,符合你SQL里select * from ReceivedFaxes的需求。 - 补充关联条件到查询谓词中,避免后续分页计数逻辑遗漏
Account的UUID过滤条件,导致分页总数计算错误。
修正后的代码如下:
public Page<ReceivedFax> findAllWithFilters(PageRequest pageRequest, Map<String, String> receivedFaxSearchCriteriaMap, String uuid) { CriteriaQuery<ReceivedFax> criteriaQuery = criteriaBuilder.createQuery(ReceivedFax.class); Root<ReceivedFax> receivedFaxRoot = criteriaQuery.from(ReceivedFax.class); // 关联Account,默认使用实体类注解配置的外键关联,对应SQL的A.ID = ReceivedFaxes.AccountID Join<ReceivedFax, Account> join = receivedFaxRoot.join("account"); // 构造合并后的查询条件 Predicate accountPredicate = criteriaBuilder.equal(join.get("uuid"), uuid); Predicate searchPredicate = getPredicate(receivedFaxSearchCriteriaMap, receivedFaxRoot); Predicate finalPredicate = criteriaBuilder.and(accountPredicate, searchPredicate); criteriaQuery.where(finalPredicate); TypedQuery<ReceivedFax> typedQuery = entityManager.createQuery(criteriaQuery); typedQuery.setFirstResult(pageRequest.getPageNumber() * pageRequest.getPageSize()); typedQuery.setMaxResults(pageRequest.getPageSize()); // getReceivedFaxCount需传入包含Account过滤的finalPredicate,保证计数准确 long receivedFaxCount = getReceivedFaxCount(finalPredicate); return new PageImpl<>(typedQuery.getResultList(), pageRequest, receivedFaxCount); }
额外注意事项
- 请确认
ReceivedFax实体类中account属性的关联注解配置正确,示例配置参考:@ManyToOne @JoinColumn(name = "AccountID") private Account account;,保证关联逻辑和原生SQL一致。 - 如果需要返回结果中同时加载关联的
Account对象,只需将account属性配置为急加载FetchType.EAGER,或者在关联时指定为抓取连接receivedFaxRoot.fetch("account")即可,不需要修改select逻辑。
内容的提问来源于stack exchange,提问作者Ilkin Mehdiyev
相关产品推荐
相关产品推荐

