Hibernate新手求助:如何在WHERE子句中使用SUBSTRING
在Hibernate Criteria查询中使用SUBSTRING构建WHERE子句
嘿,作为Hibernate初学者,想要在Criteria查询里用SUBSTRING其实不难,我结合你的现有代码一步步给你讲清楚:
首先得明确你要对哪个字段做子串截取——假设你的实体类(对应daoClass)里有个目标字段,要么是字符串类型(比如存储成ddMMyyyy格式),要么是Date类型需要先转成字符串。下面分两种常见场景给你示例:
场景1:实体字段是字符串类型(存储为ddMMyyyy格式)
比如你想把传入的valDate转成ddMMyyyy格式后,和表中字段的某部分子串(比如年份、月份)做比较,可以这样修改代码:
public List<Table> getDaoByDate(Date valDate, boolean checkPast, Class daoClass) { EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); CriteriaBuilder builder = factory.getCriteriaBuilder(); CriteriaQuery criteriaQuery = builder.createQuery(daoClass); Root<?> table = criteriaQuery.from(daoClass); criteriaQuery.select(table); SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy"); String valDateStr = sdf.format(valDate); String[] let = { "A", "B", "CD" }; // 你原本的变量 // 1. 构建SUBSTRING查询的条件:截取表中dateStr字段的年份部分(SQL的SUBSTRING是1-based索引,第5-8位) Expression<String> tableYearSub = builder.substring(table.get("dateStr"), 5, 4); String valYear = valDateStr.substring(4); // Java的substring是0-based,从索引4开始取年份 Predicate yearMatch = builder.equal(tableYearSub, valYear); // 2. 结合checkPast参数添加时间范围条件 Predicate dateRangePredicate; Expression<String> tableDateStr = table.get("dateStr"); if (checkPast) { // 查询日期早于等于valDate的记录 dateRangePredicate = builder.lessThanOrEqualTo(tableDateStr, valDateStr); } else { // 查询日期晚于等于valDate的记录 dateRangePredicate = builder.greaterThanOrEqualTo(tableDateStr, valDateStr); } // 3. 把所有条件加入WHERE子句 criteriaQuery.where(builder.and(yearMatch, dateRangePredicate)); List<Table> result = em.createQuery(criteriaQuery).getResultList(); em.getTransaction().commit(); em.close(); return result; }
场景2:实体字段是Date类型
如果你的实体字段是Date类型,不能直接截取,需要先调用数据库的格式化函数把Date转成字符串,再用SUBSTRING:
这里以MySQL的DATE_FORMAT函数为例(Oracle可以用TO_CHAR,格式参数对应调整即可):
public List<Table> getDaoByDate(Date valDate, boolean checkPast, Class daoClass) { EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); CriteriaBuilder builder = factory.getCriteriaBuilder(); CriteriaQuery criteriaQuery = builder.createQuery(daoClass); Root<?> table = criteriaQuery.from(daoClass); criteriaQuery.select(table); SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy"); String valDateStr = sdf.format(valDate); String[] let = { "A", "B", "CD" }; // 1. 把Date字段转成ddMMyyyy格式的字符串(调用MySQL的DATE_FORMAT函数) Expression<String> tableDateStr = builder.function( "DATE_FORMAT", String.class, table.get("valDate"), // 实体中的Date字段 builder.literal("%d%m%Y") // 匹配ddMMyyyy的格式参数 ); // 2. 截取年份部分做比较 Expression<String> tableYearSub = builder.substring(tableDateStr, 5, 4); String valYear = valDateStr.substring(4); Predicate yearMatch = builder.equal(tableYearSub, valYear); // 3. 结合checkPast添加范围条件 Predicate dateRangePredicate; if (checkPast) { dateRangePredicate = builder.lessThanOrEqualTo(tableDateStr, valDateStr); } else { dateRangePredicate = builder.greaterThanOrEqualTo(tableDateStr, valDateStr); } criteriaQuery.where(builder.and(yearMatch, dateRangePredicate)); List<Table> result = em.createQuery(criteriaQuery).getResultList(); em.getTransaction().commit(); em.close(); return result; }
关键注意点
- Hibernate的
CriteriaBuilder.substring()遵循SQL的索引规则,起始位置是1-based,和Java原生的String.substring()(0-based)不一样,别搞混了! - 如果是Date类型字段,要根据你使用的数据库选择对应的格式化函数,通过
builder.function()调用数据库原生方法。 - 可以用
builder.and()/builder.or()组合多个Predicate,灵活构建复杂的WHERE条件。
内容的提问来源于stack exchange,提问作者sala
相关产品推荐
相关产品推荐

