java - JPA CriteriaBuilder - 如何将具有不同动态类型的参数添加到标准?出现不明确的调用错误

标签 java jpa spring-data-jpa criteria-api jpa-2.1

我是 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/

相关文章:

java - DDD 和 Spring JPA

java - JComboBox getSelectedItem 返回正确的值但 .equals 不工作

Java/C# 程序访问 Oracle 数据库,字符串中的字符错误

java - JPA-Hibernate-从 Select 语句生成的 ID 值

java - 如何在 JPA 中从只有一列的表创建 id 生成器

java - 即使通过 Spring Boot 在架构中指定,H2 数据库也无法在列中设置默认值

java - Spring Boot中的多子句查询

java - 如何使用 Hibernate 将 Postgres _INT8 映射到 Java 实体?

java - 使用数组和可变长度形式参数。 (java :38: error: '.class' expected)

java - 查询必须以 SELECT 或 FROM : delete [delete 开头