SpringBoot3+Hibernate6.4.4中CriteriaBuilder upper()类型不匹配问题求助
问题解决:Hibernate 6 Criteria API upper() 类型不匹配错误
问题场景
使用Spring Boot 3.x + Hibernate 6.4.4.Final + MySQL,编写JPA Like查询Predicate方法时,遇到错误:
Parameter 1 of function 'upper()' has type 'STRING', but argument is of type 'java.lang.String'
原代码如下:
public static Predicate like(@NotNull CriteriaBuilder c, @NotNull Path<String> path, @NotNull String str) { return c.like(c.upper(path), "%" + str.toUpperCase().replace("/", "//").replace("_", "/_").replace("%", "/%") + "%", '/'); } public static Predicate like(@NotNull CriteriaBuilder c, @NotNull Expression<String> expression, @NotNull String str) { return c.like(c.upper(expression), "%" + str.toUpperCase().replace("/", "//").replace("_", "/_").replace("%", "/%") + "%", '/'); }
问题原因
Hibernate 6对Criteria API的类型检查变得更加严格,直接传入Java层面处理后的字符串(如str.toUpperCase()生成的java.lang.String)作为like方法的参数,会导致Hibernate无法正确映射到数据库的STRING类型,进而触发类型不匹配错误。此外,直接在Java代码中处理字符串大写和转义,也不符合JPA Criteria API的表达式模型设计。
解决方案
通过CriteriaBuilder的API来处理字符串的大写转换和字面量包装,确保所有参数都符合Hibernate的类型要求:
public static Predicate like(@NotNull CriteriaBuilder c, @NotNull Path<String> path, @NotNull String str) { // 处理查询字符串的转义逻辑 String escapedStr = "%" + str.replace("/", "//").replace("_", "/_").replace("%", "/%") + "%"; // 使用CriteriaBuilder的upper和literal方法包装表达式 Expression<String> upperPath = c.upper(path); Expression<String> upperLiteral = c.upper(c.literal(escapedStr)); return c.like(upperPath, upperLiteral, '/'); } public static Predicate like(@NotNull CriteriaBuilder c, @NotNull Expression<String> expression, @NotNull String str) { String escapedStr = "%" + str.replace("/", "//").replace("_", "/_").replace("%", "/%") + "%"; Expression<String> upperExpr = c.upper(expression); Expression<String> upperLiteral = c.upper(c.literal(escapedStr)); return c.like(upperExpr, upperLiteral, '/'); }
关键修改点
- 移除Java层面的
toUpperCase()调用,改用c.upper(c.literal(escapedStr))让Hibernate在SQL层面处理大写转换,确保类型匹配。 - 使用
c.literal()将转义后的字符串包装为Expression<String>,符合like方法对表达式类型的要求。 - 保留原有的转义逻辑,确保通配符和转义字符的处理正确。
如果上述修改仍未解决问题,可尝试显式指定Path的类型:
Expression<String> upperPath = c.upper(path.as(String.class));
内容的提问来源于stack exchange,提问作者FlorentS
相关产品推荐
相关产品推荐

