我是 JPA 的新手,并且遇到了一个相当简单的用例。我想要的只是根据某些过滤器用户传递到我的应用程序,向我的标准添加一些条件。用户使用键、值对将信息传递给应用程序,我们将对其进行解码以查看每个参数的类型。
例如:
1) 键=id 且值=20。我们将其解释为通过 id=20 进行搜索,其中 id 是整数
2) key=name 和 value='test'。我们将其解释为按 name='test' 进行搜索,其中 name 是字符串
这是通过这样的方法实现的
public <T> T getSearchValue(Object inputValue) {
if (condition) {
return (T) inputValue.toString();
} else {
return (T) Integer.parseInt(inputValue.toString);
}
}
我想我可以使用标准生成器轻松添加条件。像这样的事情
cb.equal(getSearchKey(), getSearchValue(inputValue));
cb.gt(getSearchKey(), getSearchValue(inputValue));
这里cb.equal
工作正常。但是cb.gt
或任何其他操作,如 lessThan
, like
等都给出了编译错误,有 2 个方法匹配,因此不明确
第一个方法是gt(Expression<? extends Number>, Expression<? extends Number>)
第二个是gt(Expression<? extends Number>, Number)
那么我该如何解决这个问题并确保它可以解析为 Number 作为第二个参数?这里的问题是我事先不知道类型,因为它是根据用户想要搜索的关键内容添加的。是否可以以某种方式动态转换为类,或者这里还有其他更好的方法吗?
最佳答案
想法是为“SQL 语句”的 where 子句提供限制。
SELECT * FROM table_name WHERE key=value
很多人喜欢编写类似于 SQL 的 JPQL 查询,因为阅读时更容易理解。尽管如此,使用此 Criteria API 还是有一些优点(动态、不易出错、较少关注安全性、更容易重构)。
第一步是获取CriteriaBuilder
,然后用它创建一个CriteriaQuery
。之后,您可以继续定义要从哪个类构建 Root
并使用它来获取列。加入也可以遵循。
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<YourClass> cq = cb.createQuery(YourClass.class);
Root<YourClass> root = cq.from(YourClass.class);
下一步,您需要定义 where 子句及其限制(谓词)。与普通 SQL 语句一样,只能有一个 where。如果您有多个限制,则必须将它们与 criteriaBuilder.and()
组合起来。
有多种方法可以应用整个过程。我有一种方法可以做到这一点(其他一些人也可能这样做)。通常,我创建一个包含我想要使用的所有限制的 List
,并从中创建一个数组,然后将其与 cb.and()
组合。
List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(root.get("key1"), "value1"));
predicates.add(cb.gt(root.get("key2"), 100));
cq.select(root).where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
下面是此类 DAO 方法的完整示例。
public List<Foo>(String state, int size, String column, String value) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Foo> cq = cb.createQuery(Foo.class);
Root<Foo> root = cq.from(Foo.class);
List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(root.get(Foo_.bla), state));
predicates.add(cb.gt(root.get(Foo_.blub), size));
predicates.add(cb.equal(root.get(column), value));
cq.select(root).where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
return entityManager.createQuery(cq).getResultList();
}
为了获取列名称(或单一属性),我使用了 hibernate-jpamodelgen。看看这个插件,它会自动生成带有下划线的类(例如 Foo_
),这使得使用列名称时更加类型安全。
更新:如果您事先不知道 where 子句中的限制的列名称,则调整它很简单(请参阅上面的第三个限制)。
关于java - JPA CriteriaBuilder - 如何将具有不同动态类型的参数添加到标准?出现不明确的调用错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58210590/