使用Criteria Builder构建多对多关联查询报错:ServiceBoat、ContractDocument与中间实体ContractDocumentService的关联问题
解决Criteria Builder多对多关联查询的报错问题
嘿,我来帮你搞定这个问题!你遇到的Cannot join to attribute of basic type错误,核心原因是你误用了基础类型的id字段来做关联——Criteria Builder只能基于实体之间的关联属性(比如@OneToMany/@ManyToOne标注的字段)来创建Join,而id是普通的基础类型字段,没法用来关联两个实体。
第一步:确认实体类的关联映射是否正确
首先得保证你的三个实体类之间的关联注解是正确的,这是Criteria Builder能正确关联的前提:
- ServiceBoat 类:需要包含一个指向中间表实体的集合属性
@Entity public class ServiceBoat { @Id private Long id; // 关联中间表,mappedBy对应中间表中指向ServiceBoat的字段名 @OneToMany(mappedBy = "serviceBoat") private Set<ContractDocumentServiceModel> contractDocumentServices; // 其他字段和getter/setter } - ContractDocumentServiceModel 类:作为中间表实体,需要包含两个ManyToOne关联字段
@Entity public class ContractDocumentServiceModel { @Id private Long id; @ManyToOne @JoinColumn(name = "service_boat_id") private ServiceBoat serviceBoat; @ManyToOne @JoinColumn(name = "contract_document_id") private ContractDocument contractDocument; // 其他字段和getter/setter } - ContractDocument 类:同样包含指向中间表实体的集合属性
@Entity public class ContractDocument { @Id private Long id; @OneToMany(mappedBy = "contractDocument") private Set<ContractDocumentServiceModel> contractDocumentServices; // 其他字段和getter/setter }
第二步:编写正确的Criteria Builder关联代码
现在你可以基于实体的关联属性来创建Join了,替换掉之前错误的join("id")写法:
// 初始化Criteria相关对象 CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<ServiceBoat> query = cb.createQuery(ServiceBoat.class); // 从ServiceBoat作为root Root<ServiceBoat> rootServiceBoat = query.from(ServiceBoat.class); // 第一步:关联ServiceBoat和中间表ContractDocumentServiceModel // 这里的"contractDocumentServices"是ServiceBoat类中定义的关联集合属性名 Join<ServiceBoat, ContractDocumentServiceModel> joinToMiddleTable = rootServiceBoat.join("contractDocumentServices", JoinType.INNER); // 第二步:从中间表关联到ContractDocument // 这里的"contractDocument"是中间表类中定义的关联字段名 Join<ContractDocumentServiceModel, ContractDocument> joinToContractDocument = joinToMiddleTable.join("contractDocument", JoinType.INNER); // 后续可以添加查询条件,比如: // query.where(cb.equal(joinToContractDocument.get("id"), 1L)); // 执行查询 List<ServiceBoat> result = entityManager.createQuery(query).getResultList();
关键注意点
- 一定要用实体类中定义的关联属性名来创建Join,而不是数据库表的字段名或者基础类型字段
- 如果你的实体关联属性名字和示例不一样(比如ServiceBoat里的集合叫
serviceBoatLinks),记得替换成你自己的字段名 - 可以根据业务需求调整JoinType(INNER/LEFT等)
内容的提问来源于stack exchange,提问作者rafaelpadu
相关产品推荐
相关产品推荐

