比较 JPA Criteria API 中的日期实体

Posted

技术标签:

【中文标题】比较 JPA Criteria API 中的日期实体【英文标题】:Compare Date entities in JPA Criteria API 【发布时间】:2012-03-15 23:32:03 【问题描述】:

将 JPA 2 与 EclipseLink 实现结合使用。

我正在尝试构建一个动态查询,它应该会为我带来一些在给定日期后保留的记录。

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Event> criteria = builder.createQuery(Event.class);
Root<Event> root = criteria.from(Event.class);
criteria.select(root);
criteria.distinct(true);
List<Predicate> predicates = new ArrayList<Predicate>();
//...
if (dateLimit != null)
    ParameterExpression<Date> param = builder.parameter(Date.class, "dateLimit");
    predicates.add(builder.lessThanOrEqualTo(root.get("dateCreated"), param));

lessThanOrEqualTo()le() 是 API 中仅有的两个方法,在这种情况下看起来可能对我有帮助。不过这个警告是由 eclipse 抛出的:

Bound mismatch: The generic method lessThanOrEqualTo(Expression<? extends Y>, Expression<? extends Y>)
of type CriteriaBuilder is not applicable for the arguments (Path<Object>, ParameterExpression<Date>).
The inferred type Object is not a valid substitute for the bounded parameter
<Y extends Comparable<? super Y>>

我可以想象我没有采取正确的方法来解决这个问题,但我在任何地方都找不到可能的解决方案的提示或指示。

【问题讨论】:

【参考方案1】:

问题在于,使用基于字符串的 API,它无法推断 get-Operation 的结果值的类型。例如,Javadoc for Path 对此进行了解释。

如果你使用

predicates.add(builder.lessThanOrEqualTo(root.<Date>get("dateCreated"), param));

相反,它会正常工作,因为它可以从类型参数中找出返回类型,并且会发现它是可比较的。请注意,使用参数化方法调用 root.&lt;Date&gt;get(...)(参见,例如,When is a parameterized method call useful?)。

另一个(我认为更好的)解决方案是使用基于元模型的 API 而不是基于字符串的 API。给出了一个关于规范元模型的简单示例,例如 here。如果你有更多的时间投入,这是一篇关于静态元模型的好文章:Dynamic, typesafe queries in JPA 2.0

【讨论】:

NetBeans 8.2 仍然使用标准发出警告。我不知道为什么。 builder.greaterThanOrEqualsTo(root.get(Some_.date), date) builder.greaterThanOrEqualsTo(root.&lt;Date&gt;get(Some_.date), date) @Jin Kwon:确保导入javax.persistence.criteria.Predicate,而不是java.util.function.Predicate。这为我解决了问题:) 不是一个糟糕的导入问题,它是一个错误,一个非常古老的错误。要解决此问题,您必须将其声明为变量并将其用作参数:Path path = root.get( .....); builder.greaterThan(path, date);【参考方案2】:

您需要使用生成的元模型来访问属性是一种非常安全的方式。如果您使用字符串来引用您的属性,则类型只能从调用方法时使用的显式泛型类型推导出来,或者通过类型转换,或者通过编译器完成的自动类型推断:

Path<Date> dateCreatedPath = root.get("dateCreated");
predicates.add(builder.lessThanOrEqualTo(dateCreatedPath, dateLimit));

【讨论】:

【参考方案3】:

我遇到了类似的错误,但语法为 predicates.add(cb.greaterThan(article.get(Article_.created), since)); 并找到了此页面。对我来说,原因是我已经将我的项目从 Java 1.7 升级到了 1.8,并且在此过程中还配置了 Maven 以编译 Java 1.8。我只需将 Maven 编译更改回 1.7,同时将项目的其余部分保持在 1.8,即可修复错误。

【讨论】:

【参考方案4】:

当我使用谓词时,我遇到了同样的问题。它适用于除日期类型以外的所有类型。我尝试了所有方法,对我来说最简单的方法是:

predicates.add(builder.greaterThanOrEqualTo(root.get(criteria.getKey()), (Date)criteria.getValue()));

我在criteria.getValue() 之前添加了(Date),这有助于将我的值 Object 识别为 Date 类型。

【讨论】:

以上是关于比较 JPA Criteria API 中的日期实体的主要内容,如果未能解决你的问题,请参考以下文章

jpa criteria-api:加入子选择

JPA & Criteria API - 仅选择特定列

JPA/Criteria API - Like & equal 问题

Jersey API + JPA/Hibernate Criteria延迟加载不起作用

JPA Criteria Query API 和两列排序

Criteria API JPA Hibernate:外键上的不同选择