CriteriaBuilder IN查询报错:无法转换List类型值的技术咨询
JPA Criteria API 集合in查询的类型转换异常排查与解决
这个问题我之前在使用JPA Criteria API的时候也踩过坑,咱们一步步来分析原因和解决办法:
异常原因
这个IllegalArgumentException的核心问题出在idField.in(ids)这一行:
Caused by: java.lang.IllegalArgumentException: Unaware how to convert value [[100, 101] : java.util.ArrayList]
部分JPA提供者(比如特定版本的Hibernate)在处理Path.in(Collection)方法时,会错误地将整个List集合作为单个参数传入查询,而不是把List中的元素逐一拆解成多个匹配值。这就导致JPA试图把ArrayList对象转换成Integer类型去匹配id字段,最终触发类型转换异常。
解决方法
方案1:将List转换为数组传入
in()方法原生支持可变参数或数组类型,把List转为对应的数组后传入,就能让JPA正确识别每个元素:
public Iterable<T> findAllByIds(List<Integer> ids) { Path<Integer> idField = root.get("id"); // 将List转为Integer数组,避免集合被当成单个参数 Predicate in = idField.in(ids.toArray(new Integer[0])); query.select(root); query.where(in); query.orderBy(builder.asc(idField)); List<T> result = entityManager.createQuery(query).getResultList(); return result; }
方案2:使用CriteriaBuilder构建In条件(更稳妥)
通过CriteriaBuilder.in()方法手动逐个添加值,完全符合Criteria API的规范,从根源避免集合参数的识别问题:
public Iterable<T> findAllByIds(List<Integer> ids) { Path<Integer> idField = root.get("id"); // 用CriteriaBuilder创建In条件,逐个添加值 In<Integer> inClause = builder.in(idField); for (Integer id : ids) { inClause.value(id); } query.select(root); query.where(inClause); query.orderBy(builder.asc(idField)); List<T> result = entityManager.createQuery(query).getResultList(); return result; }
方案3:升级JPA提供者版本
如果上述两种方法都无效,大概率是你使用的JPA提供者(比如Hibernate)存在版本bug。建议升级到最新的稳定版本(例如Hibernate 5.4+),这类集合参数的识别问题在新版本中已经被官方修复。
内容的提问来源于stack exchange,提问作者Антон Итунин
相关产品推荐
相关产品推荐

