2012-02-25 11 views
34

Uso de JPA 2 con implementación de EclipseLink.Comparar entidades de fecha en los criterios de JPA API

Estoy tratando de crear una consulta dinámica que debería traer algunos registros persistentes después de una fecha determinada.

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() y le() son los únicos dos métodos en la API, que se parecen a mí puede ayudar en este caso. Esta advertencia es arrojado por el eclipse sin embargo:

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

puedo imaginar que no estoy tomando el enfoque correcto para este problema, pero no puedo encontrar en cualquier lugar algunos consejos o sugerencias para una posible solución.

Respuesta

58

El problema es que con la API basada en cadenas no puede inferir el tipo para el valor de resultado de get -Operation. Esto se explica, por ejemplo, en Javadoc for Path.

Si utiliza

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

en cambio, no tendrán ningún problema, ya que puede averiguar el tipo de retorno desde el argumento de tipo y descubrir que es comparable. Tenga en cuenta el uso de una invocación al método parametrizado root.<Date>get(...) (ver, por ejemplo, When is a parameterized method call useful?).

Otra solución (en mi opinión, mejor) es utilizar la API basada en metamodelo en lugar de la basada en cadenas. Un ejemplo simple sobre metamodelo canónico se da, por ejemplo, here. Si tiene más tiempo para invertir, este es un buen artículo sobre metamodelo estático: Dynamic, typesafe queries in JPA 2.0

+1

NetBeans 8.2 todavía advierte con criterios. No sé por qué. 'builder.greaterThanOrEqualsTo (root.get (Some_.date), date)' <> 'builder.greaterThanOrEqualsTo (root . get (Some_.date), date)' –

+0

@Jin Kwon: asegúrese de importar 'javax.persistence .criteria.Predicate', not 'java.util.function.Predicate'. Eso lo solucionó :) – Hank

+0

No es un problema de importación, es un error, muy antiguo. para solucionarlo, debe declararlo como una variable y usarlo como parámetro: 'Path path = root.get (.....); builder.greaterThan (ruta, fecha); ' – FiruzzZ

12

Necesita usar el metamodelo generado para acceder a los atributos de una manera realmente segura. Si se utilizan cadenas para referirse a sus atributos, tipos sólo pueden ser deducidas de tipo genérico explícita utilizada cuando se llama al método o por un elenco tipo, o por la inferencia de tipo automático realizado por el compilador:

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

Obtuve un error similar pero con la sintaxis predicates.add(cb.greaterThan(article.get(Article_.created), since)); y encontré esta página. La causa para mí, resultó ser que había actualizado mi proyecto de Java 1.7 a 1.8, y en el proceso también había configurado Maven para compilar para Java 1.8. Simplemente tuve que cambiar las compilaciones de Maven a 1.7, mientras mantenía el resto del proyecto en 1.8, para arreglar el error.

Cuestiones relacionadas