web-dev-qa-db-fra.com

Comparer les entités Date dans l'API JPA Criteria

tilisation de JPA 2 avec l'implémentation EclipseLink.

J'essaie de construire une requête dynamique qui devrait m'apporter des enregistrements persistants après une date donnée.

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() et le() sont les deux seules méthodes de l'API qui pourraient m'aider dans ce cas. Cet avertissement est lancé par l'Eclipse cependant:

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>>

Je peux imaginer que je n'adopte pas la bonne approche pour ce problème, mais je ne trouve nulle part des conseils ou des conseils pour une solution possible.

42
Ionut

Le problème est qu'avec l'API basée sur des chaînes, il ne peut pas déduire le type de la valeur de résultat de l'opération get-. Ceci est expliqué par exemple dans Javadoc pour Path .

Si tu utilises

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

au lieu de cela, cela fonctionnera bien, car il peut déterminer le type de retour à partir de l'argument type et découvrira qu'il est comparable. Remarque, l'utilisation d'une invocation de méthode paramétrée root.<Date>get(...) (voir, par exemple, Quand un appel de méthode paramétré est-il utile? ).

Une autre solution (à mon avis meilleure) consiste à utiliser l'API basée sur le métamodèle au lieu de celle basée sur les chaînes. Un exemple simple sur le métamodèle canonique est donné par exemple ici . Si vous avez plus de temps à investir, voici un bon article sur le métamodèle statique: requêtes dynamiques et sécurisées dans JPA 2.

71
Mikko Maunu

Vous devez utiliser le métamodèle généré pour accéder aux attributs est un moyen très sûr. Si vous utilisez des chaînes pour faire référence à vos attributs, les types ne peuvent être déduits que du type générique explicite utilisé lors de l'appel de la méthode, ou par une conversion de type, ou par l'inférence de type automatique effectuée par le compilateur:

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

J'obtenais une erreur similaire mais avec la syntaxe predicates.add(cb.greaterThan(article.get(Article_.created), since)); et j'ai trouvé cette page. La cause pour moi s'est avérée être que j'avais mis à niveau mon projet de Java 1.7 à 1.8, et dans le processus, j'avais configuré Maven pour compiler pour Java 1.8 aussi. J'ai simplement dû changer les compilations de Maven à 1.7, tout en maintenant le reste du projet à 1.8, pour corriger l'erreur.

2
Bjørn Stenfeldt