比较 JPA 标准 API 中的日期实体

2022-08-31 17:12:43

将 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()并且是API中仅有的两种方法,在这种情况下看起来可能会对我有所帮助。不过,这个警告是由日食引发的:le()

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,它无法推断出 -Operation 的结果值的类型。例如,在Javadoc for Path中对此进行了解释。get

如果您使用

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

相反,它可以正常工作,因为它可以从类型参数中找出返回类型,并会发现它是可比较的。请注意,使用参数化方法调用(例如,请参阅参数化方法调用何时有用?)。root.<Date>get(...)

另一个(在我看来更好)解决方案是使用基于元模型的API,而不是基于字符串的API。例如,这里给出了一个关于规范元模型的简单示例。如果您有更多的时间投入,这是一篇关于静态元模型的好文章:JPA 2.0中的动态,类型安全的查询


答案 2

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

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