如何构造CriteriaQuery判断指定字符串是否在实体List<String>字段中
解决方案
你通过@Convert将List<String>序列化为JSON字符串存储在数据库中,JPA Criteria API 默认会将names字段识别为普通字符串类型,无法直接用集合相关的查询方法,需要调用数据库原生的JSON处理函数构造查询条件。
场景1:使用MySQL数据库
MySQL提供JSON_CONTAINS函数用于判断JSON数组是否包含指定元素,直接调用该函数构造Predicate即可:
restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.function( "JSON_CONTAINS", Boolean.class, root.get("names"), // 注意要给查询值包裹双引号,符合JSON字符串格式要求 criteriaBuilder.literal("\"" + inName + "\""), // $表示匹配整个JSON根路径 criteriaBuilder.literal("$") ) );
场景2:使用PostgreSQL数据库
PostgreSQL可以通过jsonb_contains函数判断JSON数组包含关系,写法如下:
restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.function( "jsonb_contains", Boolean.class, // 将数据库存储的字符串转为jsonb类型 criteriaBuilder.function("to_jsonb", Object.class, root.get("names")), // 将查询值转为jsonb类型的单个元素 criteriaBuilder.function("to_jsonb", Object.class, criteriaBuilder.literal(inName)) ) );
注意事项
- 不推荐使用
LIKE模糊匹配实现该需求,比如criteriaBuilder.like(root.get("names"), "%\"" + inName + "\"%"),这种写法存在误匹配风险,比如元素值包含目标字符串的情况会被错误命中。 - 如果你使用的是其他数据库,可以替换为对应数据库的JSON包含函数,逻辑和上面两种场景一致。
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

