Hibernate JPA:如何查询transid去重的Orders实体
问题分析
你的代码抛出ClassCastException的原因很明确:cq.select(root.get("transid"))指定查询的是transid字段(String类型),但CriteriaQuery<Orders>声明要返回Orders实体,Hibernate无法将String类型的结果强制转换为Orders对象,因此报错。
解决方案
以下是几种实现“查询去重transid对应的Orders实体”的可行方式,你可以根据业务场景选择:
方案一:子查询获取去重transid,再查询对应实体
先通过子查询拿到所有去重的transid,再以此为条件查询完整的Orders实体,适用于一个transid对应多个实体且需要全部返回的场景:
public List<Orders> custOrder() { try (Session session = HibernateUtil.getSessionFactory().openSession()) { CriteriaBuilder cb = session.getCriteriaBuilder(); // 子查询:获取所有去重的transid CriteriaQuery<String> subQuery = cb.createQuery(String.class); Root<Orders> subRoot = subQuery.from(Orders.class); subQuery.select(subRoot.get("transid")).distinct(true); // 主查询:根据去重的transid查询完整Orders实体 CriteriaQuery<Orders> mainQuery = cb.createQuery(Orders.class); Root<Orders> mainRoot = mainQuery.from(Orders.class); mainQuery.select(mainRoot) .where(mainRoot.get("transid").in(subQuery)); return session.createQuery(mainQuery).getResultList(); } }
方案二:分组获取每组唯一实体
如果一个transid对应多个实体,但你只需要每组中的一个实体(比如取主键最大/最小的记录),可以用分组+聚合函数实现:
public List<Orders> custOrder() { try (Session session = HibernateUtil.getSessionFactory().openSession()) { CriteriaBuilder cb = session.getCriteriaBuilder(); // 子查询:按transid分组,获取每组的Orders主键(假设id是主键字段) CriteriaQuery<Long> subQuery = cb.createQuery(Long.class); Root<Orders> subRoot = subQuery.from(Orders.class); subQuery.select(cb.max(subRoot.get("id"))) // 用max或min选择每组的一条记录 .groupBy(subRoot.get("transid")); // 主查询:根据主键查询完整Orders实体 CriteriaQuery<Orders> mainQuery = cb.createQuery(Orders.class); Root<Orders> mainRoot = mainQuery.from(Orders.class); mainQuery.select(mainRoot) .where(mainRoot.get("id").in(subQuery)); return session.createQuery(mainQuery).getResultList(); } }
方案三:直接对实体去重(仅适用于transid唯一的场景)
如果transid是业务唯一键,且相同transid的实体所有字段完全一致,或者你的Orders实体的equals和hashCode方法是基于transid实现的,可以直接对实体使用distinct:
public List<Orders> custOrder() { try (Session session = HibernateUtil.getSessionFactory().openSession()) { CriteriaBuilder cb = session.getCriteriaBuilder(); CriteriaQuery<Orders> cq = cb.createQuery(Orders.class); Root<Orders> root = cq.from(Orders.class); cq.select(root).distinct(true); return session.createQuery(cq).getResultList(); } }
内容的提问来源于stack exchange,提问作者Daily JavaFX
相关产品推荐
相关产品推荐

