如何使用Hibernate Criteria API按多对多关联属性对实体排序
多对多关联下实体排序Hibernate Criteria实现方案
核心逻辑
你的需求本质是将每个Field实体关联的所有Crop中,字典序最小的name作为Field本身的排序依据,按该值升序排列即可匹配预期结果。实现时需要通过多对多关联join后做分组聚合,同时避免多对多关联产生重复的Field记录。
Hibernate Legacy Criteria 实现代码
// 第一步:查询按最小Crop name排序后的Field id列表 Criteria idCriteria = session.createCriteria(Field.class); idCriteria.createAlias("crops", "crop", JoinType.LEFT_OUTER_JOIN); idCriteria.setProjection(Projections.projectionList() .add(Projections.groupProperty("id"), "fieldId") .add(Projections.min("crop.name"), "minCropName") ); idCriteria.addOrder(Order.asc("minCropName")); List<Long> orderedFieldIds = idCriteria.list().stream() .map(obj -> (Long) ((Object[]) obj)[0]) .toList(); // 第二步:按排序后的id列表查询完整的Field实体,保留关联集合加载逻辑 Criteria fieldCriteria = session.createCriteria(Field.class); fieldCriteria.add(Restrictions.in("id", orderedFieldIds)); // 保证查询结果顺序和id列表顺序一致 fieldCriteria.addOrder(Order.asc( "case id " + orderedFieldIds.stream() .map(id -> "when " + id + " then " + orderedFieldIds.indexOf(id)) .collect(Collectors.joining(" ")) + " end" )); List<Field> result = fieldCriteria.list();
JPA 标准Criteria API 实现代码(Hibernate 5.2+推荐使用)
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<Field> cq = cb.createQuery(Field.class); Root<Field> fieldRoot = cq.from(Field.class); // 左连接关联crops集合,兼容没有关联Crop的Field ListJoin<Field, Crop> cropJoin = fieldRoot.joinList("crops", JoinType.LEFT); // 按Field主键分组,避免多对多关联产生重复Field记录 cq.groupBy(fieldRoot.get("id")); // 按每个Field关联的最小Crop name升序排序 cq.orderBy(cb.asc(cb.min(cropJoin.get("name")))); // 执行查询得到结果 TypedQuery<Field> query = entityManager.createQuery(cq); List<Field> result = query.getResultList();
提示:如果需要将未关联任何Crop的Field排在结果末尾,可在排序规则中添加空值后置配置:
- JPA Criteria写法:
cb.asc(cb.min(cropJoin.get("name"))).nullsLast()- Legacy Criteria写法:
Order.asc("minCropName").nulls(NullPrecedence.LAST)
内容的提问来源于stack exchange,提问作者betta7391
相关产品推荐
相关产品推荐

