web-dev-qa-db-ja.com

JPA Criteria APIでの日付エンティティの比較

EclipseLink実装でのJPA 2の使用。

私は、特定の日付の後も保持されているいくつかのレコードをもたらす動的なクエリを構築しようとしています。

_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の2つのメソッドです。ただし、この警告は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>>
_

私はこの問題に対して正しいアプローチを取っていないと想像できますが、可能な解決策のヒントや指針をどこにも見つけることができません。

42
Ionut

問題は、文字列ベースのAPIでは、get- Operationの結果値の型を推測できないことです。これは、たとえば PathのJavadoc で説明されています。

使用する場合

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

代わりに、type引数から戻り値の型を把握でき、比較可能であることがわかるため、正常に機能します。パラメータ化されたメソッド呼び出しroot.<Date>get(...)の使用に注意してください(たとえば、 パラメータ化されたメソッド呼び出しはいつ便利ですか? を参照してください)。

別の(私の意見では)より良い解決策は、文字列ベースのAPIの代わりにメタモデルベースのAPIを使用することです。正規メタモデルに関する簡単な例は、たとえば here です。もっと投資する時間があれば、これは静的メタモデルに関する優れた記事です。 JPA 2.0の動的なタイプセーフクエリ

71
Mikko Maunu

生成されたメタモデルを使用して属性にアクセスする必要があるのは、本当に安全な方法です。文字列を使用して属性を参照する場合、型は、メソッドの呼び出し時に使用される明示的なジェネリック型、型キャスト、またはコンパイラーによる自動型推論によってのみ推定できます。

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

私は同様のエラーを受け取っていましたが、構文predicates.add(cb.greaterThan(article.get(Article_.created), since));でこのページを見つけました。私の原因は、プロジェクトをJava 1.7から1.8にアップグレードし、その過程でMavenをJava 1.8も同様に、Mavenのコンパイルを1.7に戻し、プロジェクトの残りの部分を1.8に保ち、エラーを修正する必要がありました。

2