简体   繁体   中英

Compare Date entities in JPA Criteria API

Using JPA 2 with EclipseLink implementation.

I'm trying to build a dynamic query which should bring me some records persisted after a given date.

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() and le() are the only two methods in the API which look like may help me in this case. This warning is thrown by the eclipse though:

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

I can imagine that I'm not taking the correct approach for this problem but I can't find anywhere some tips or pointers for a possible solution.

The problem is that with the string-based API it cannot infer the type for the result value of the get -Operation. This is explained for example in Javadoc for Path .

If you use

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

instead, it will work fine, because it can figure out the return type from the type argument and will find out that it is comparable. Note, the use of a parameterised method invocation root.<Date>get(...) (see, eg, When is a parameterized method call useful? ).

Another (in my opinion better) solution is to use the metamodel based API instead of the string-based one. A simple example about canonical metamodel is given for example here . If you have more time to invest, this is a good article about static metamodel: Dynamic, typesafe queries in JPA 2.0

You need to use the generated metamodel to access the attributes is a really safe way. If you use Strings to refer to your attributes, types can only be deduced from the explicit generic type used when calling the method, or by a type cast, or by the automatic type inference done by the compiler:

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

I was getting a similar error but with the syntax predicates.add(cb.greaterThan(article.get(Article_.created), since)); and found this page. The cause for me, turned out to be that I had upgraded my project from Java 1.7 to 1.8, and in the process had configured Maven to compile for Java 1.8 as well. I simply had to change Maven compiles back to 1.7, while keeping the rest of the project at 1.8, to fix the error.

I had the same problem, when I have worked with predicates. It worked great with all types except Date type. I tried all method and most simple way for me was:

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

I added (Date) before criteria.getValue() , what help to recognize my value Object as Date type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM