java - 具有非字符串类型过滤器的条件查询 - JPA/Hibernate Spring Boot
问题描述
我正在尝试使用带有过滤器的 Criteria Query 从表 MyEntity 中获取行数。
此过滤器(函数参数)是一个 JsonNode,其中键(JsonNode 过滤器)作为实体中的列,值(JsonNode 过滤器)可以是 String 或 JsonNode 类型,具体取决于用户传递的过滤器。
例如。
如果过滤器是{"policy": {"id": "123"}}
,则搜索policy
具有 json 类型值的列{"id": "123"}
,
如果 filter 是{"string_column": "test_string"}
,则搜索string_column
具有字符串类型值的列test_string
。
使用的数据库是 PostgreSQL。
这是我的代码 -
public Long getCountForMyEntity(JsonNode filter) {
CriteriaBuilder criteriaBuilder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Long> query = criteriaBuilder.createQuery(Long.class);
Root<MyEntity> root = query.from(MyEntity.class);
query.select(criteriaBuilder.count(root));
Iterator<Map.Entry<String, JsonNode>> filterFields = filter.fields();
while(filterFields.hasNext()) {
Map.Entry<String, JsonNode> field = filterFields.next();
String fieldName = field.getKey();
JsonNode fieldValue = field.getValue();
Object value = fieldValue;
System.out.println(fieldValue + " : " + fieldValue.getNodeType());
if (fieldValue.getNodeType() == JsonNodeType.STRING) {
value = fieldValue.asText();
}
query.where(criteriaBuilder.equal(root.get(fieldName), value));
}
return sessionFactory.getCurrentSession().createQuery(query).getSingleResult();
}
当过滤器值为字符串但过滤器值为 json 时,这适用于获取计数,我收到以下错误 -
44- [WARN ] 2021-10-26 14:42:35 [http-nio-9090-exec-7] o.h.e.j.s.SqlExceptionHelper [][][][] - SQL Error: 0, SQLState: 42883
45- [ERROR] 2021-10-26 14:42:35 [http-nio-9090-exec-7] o.h.e.j.s.SqlExceptionHelper [][][][] - ERROR: operator does not exist: json = unknown
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Position: 121
46- [WARN ] 2021-10-26 14:42:35 [http-nio-9090-exec-7] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [][][][] - Resolved [org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet]
我试过像这样直接传递fieldValue,但仍然是同样的错误-
query.where(criteriaBuilder.equal(root.get(fieldName), fieldValue));
知道我哪里出错了吗?有没有过滤json/非字符串值的好方法?
解决方案
从 Narasimha 的铸造技术中获得灵感,但铸造为 String 而不是 jsonb。在与我们传递的转换为字符串的 JsonNode 进行比较之前,它将存储在 db 中的 json 转换为 String。
query.where(criteriaBuilder.equal(root.get(fieldName).as(String.class), fieldValue.toString()));
完整代码如下所示 -
public Long getCountForMyEntity(JsonNode filter) {
CriteriaBuilder criteriaBuilder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Long> query = criteriaBuilder.createQuery(Long.class);
Root<MyEntity> root = query.from(MyEntity.class);
query.select(criteriaBuilder.count(root));
Iterator<Map.Entry<String, JsonNode>> filterFields = filter.fields();
while(filterFields.hasNext()) {
Map.Entry<String, JsonNode> field = filterFields.next();
String fieldName = field.getKey();
JsonNode fieldValue = field.getValue();
System.out.println(fieldValue + " : " + fieldValue.getNodeType());
if (fieldValue.getNodeType() == JsonNodeType.STRING) {
query.where(criteriaBuilder.equal(root.get(fieldName), fieldValue.asText()));
} else {
query.where(criteriaBuilder.equal(root.get(fieldName).as(String.class), fieldValue.toString()));
}
}
return sessionFactory.getCurrentSession().createQuery(query).getSingleResult();
}
推荐阅读
- c++ - 如何在 C++ 中的地图中存储地址?
- sql-server - 以百分比返回 SQL 结果
- javascript - 带有查询过滤器的 DynamoDB 搜索对象
- angular - 打字稿json对象查找值
- javascript - 如何在输入类型日期字段中仅重置年份?
- reactjs - && 逻辑运算符 jsx 和打字稿出错
- c# - 在继承中覆盖 Asp.net Core 的路由
- flutter - 如何从数据表中隐藏或删除列或使用颤振将其设置为不可见
- apollo-server - 如何在独立的 Apollo 应用程序中使用 Secured WebSocket (WSS)?
- mysql - 不要让用户更新 MYSQL 中的列值