如何使用JPA Criteria Builder实现多表左连接查询?
实现JPA Criteria Builder对应SQL的步骤
你已经成功创建了Alert到MarkerGroup的左连接,接下来只需要完成剩余的关联、条件添加和投影配置即可,具体步骤如下:
1. 关联Marker表
从已有的markerGroupJoin出发,左连接到Marker实体(对应SQL里的LEFT JOIN marker m ON mg.id = m.marker_group_id)。假设你的Marker实体中,关联MarkerGroup的字段名为markerGroup,代码如下:
Join<MarkerGroup, Marker> markerJoin = markerGroupJoin.join("markerGroup", JoinType.LEFT); // 若MarkerGroup是通过集合关联Marker(比如MarkerGroup有List<Marker> markers字段),则用joinCollection: // Join<MarkerGroup, Marker> markerJoin = markerGroupJoin.joinCollection("markers", JoinType.LEFT);
注意:这里的字段名要和你实体类中定义的关联属性名一致,不是数据库表的物理字段名。
2. 添加查询条件
接下来添加经纬度的过滤条件,对应SQL里的where m.latitude = '32.985173502462686' AND m.longitude='-96.89707056619227':
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<Tuple> query = cb.createTupleQuery(); Root<Alert> root = query.from(Alert.class); Join<Alert, MarkerGroup> markerGroupJoin = root.join("markerGroup", JoinType.LEFT); Join<MarkerGroup, Marker> markerJoin = markerGroupJoin.join("markerGroup", JoinType.LEFT); // 需匹配你的实体关联字段 // 构造过滤条件 Predicate latitudePredicate = cb.equal(markerJoin.get("latitude"), "32.985173502462686"); Predicate longitudePredicate = cb.equal(markerJoin.get("longitude"), "-96.89707056619227"); query.where(cb.and(latitudePredicate, longitudePredicate));
3. 配置投影字段
因为你只需要查询a.id, a.marker_group_id, a.name,所以需要指定要返回的字段:
// 选择Alert的id、MarkerGroup的id(对应marker_group_id)、Alert的name query.multiselect( root.get("id"), markerGroupJoin.get("id"), root.get("name") );
4. 执行查询并获取结果
最后执行查询,处理返回的结果:
List<Tuple> results = entityManager.createQuery(query).getResultList(); // 遍历结果示例 for (Tuple tuple : results) { Long alertId = tuple.get(root.get("id"), Long.class); Long markerGroupId = tuple.get(markerGroupJoin.get("id"), Long.class); String alertName = tuple.get(root.get("name"), String.class); // 后续业务逻辑处理 }
补充说明
- 如果你的项目中使用DTO接收结果,可以用
cb.construct()代替multiselect,比如创建一个AlertProjectionDTO包含id、markerGroupId、name字段:
CriteriaQuery<AlertProjectionDTO> query = cb.createQuery(AlertProjectionDTO.class); // ... 关联和条件部分同上 query.select(cb.construct(AlertProjectionDTO.class, root.get("id"), markerGroupJoin.get("id"), root.get("name") )); List<AlertProjectionDTO> results = entityManager.createQuery(query).getResultList();
- 注意经纬度类型:如果数据库中是数值类型(比如
DECIMAL或DOUBLE),不要用字符串传入,应该用对应的数值类型(比如Double),避免类型转换问题。
内容的提问来源于stack exchange,提问作者vinod j
相关产品推荐
相关产品推荐

