如何使用Hibernate Criteria转换指定MySQL多表关联分页查询
把MySQL查询转成Hibernate Criteria实现
嘿,这就帮你把这条MySQL查询转换成Hibernate Criteria的实现~先得明确一下对应的实体类结构,毕竟Hibernate是面向对象的ORM框架,咱们先假设你已经有了和表对应的实体:State对应tbl_state,Country对应tbl_country,而且State实体里关联了Country对象(或者至少包含countryId字段)。下面分两种常见的API写法给你参考:
一、传统Hibernate Criteria API(适合Hibernate 3/4版本)
这个写法更贴近旧版的Hibernate风格,完全对应你的原SQL逻辑:
// 获取当前Session Session session = sessionFactory.getCurrentSession(); // 创建State的Criteria查询,别名"s"对应原SQL里的"s" Criteria criteria = session.createCriteria(State.class, "s"); // 关联tbl_country表,对应原SQL里的FROM tbl_state s,tbl_country c WHERE s.country_id=c.country_id // 这里用INNER JOIN,和原SQL的隐式内联效果一致 criteria.createAlias("s.country", "c", JoinType.INNER_JOIN); // 投影查询:选择State的所有字段 + Country的countryName,对应SELECT s.*,c.country_name ProjectionList projections = Projections.projectionList(); // 把State的所有属性映射到"state"别名 projections.add(Projections.property("s"), "state"); // 把Country的countryName映射到"countryName"别名 projections.add(Projections.property("c.countryName"), "countryName"); criteria.setProjection(projections); // 用DTO来接收组合结果,需要你自己定义一个StateCountryDTO类 criteria.setResultTransformer(Transformers.aliasToBean(StateCountryDTO.class)); // 按state_name排序,对应ORDER BY s.state_name criteria.addOrder(Order.asc("s.stateName")); // 降序的话用Order.desc() // 分页逻辑:对应LIMIT pagesize OFFSET pagesize * pagenum int offset = pagesize * pagenum; criteria.setFirstResult(offset); // 设置偏移量 criteria.setMaxResults(pagesize); // 设置每页条数 // 执行查询得到结果 List<StateCountryDTO> stateList = criteria.list();
对应的StateCountryDTO示例(用来接收混合结果):
public class StateCountryDTO { private State state; // 对应原SQL的s.* private String countryName; // 对应原SQL的c.country_name // 记得添加无参构造、全参构造,以及getter/setter方法 }
二、JPA CriteriaBuilder API(适合Hibernate 5+及JPA标准)
如果你的项目用的是较新的Hibernate版本,推荐用JPA标准的CriteriaBuilder写法,更符合现代ORM规范:
// 获取EntityManager EntityManager em = entityManagerFactory.createEntityManager(); CriteriaBuilder cb = em.getCriteriaBuilder(); // 创建针对StateCountryDTO的查询 CriteriaQuery<StateCountryDTO> cq = cb.createQuery(StateCountryDTO.class); // 定义查询根,对应原SQL的tbl_state s Root<State> s = cq.from(State.class); // 关联tbl_country,自动处理s.country_id = c.country_id的条件 Join<State, Country> c = s.join("country", JoinType.INNER); // 选择需要的字段,直接构造DTO对象 cq.select(cb.construct(StateCountryDTO.class, s, c.get("countryName"))); // 按state_name排序 cq.orderBy(cb.asc(s.get("stateName"))); // 设置分页参数 int offset = pagesize * pagenum; TypedQuery<StateCountryDTO> query = em.createQuery(cq); query.setFirstResult(offset); query.setMaxResults(pagesize); // 执行查询 List<StateCountryDTO> stateList = query.getResultList();
几个注意点
- 实体类的属性要和数据库字段正确映射:比如
State的stateName要对应tbl_state的state_name,Country的countryName对应tbl_country的country_name,可以通过@Column注解配置。 - 如果你的
State实体没有关联Country对象,而是用countryId字段存储关联ID,那关联条件可以改成criteria.add(Restrictions.eqProperty("s.countryId", "c.countryId")),不过更推荐用实体关联,符合ORM的设计思想。 - 分页的偏移量计算:如果你的
pagenum是从1开始的(比如第1页、第2页),那偏移量应该改成pagesize * (pagenum - 1),避免跳过第一页数据。
内容的提问来源于stack exchange,提问作者ysk
相关产品推荐
相关产品推荐

