2012-02-25 3 views
34

Использование JPA 2 с реализацией EclipseLink.Сравнение объектов даты в JPA Критерии API

Я пытаюсь построить динамический запрос, который должен принести мне некоторые записи, сохраненные после определенной даты.

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, которые выглядят, как может мне помочь в этом случае. Это предупреждение брошено затмение, хотя:

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

Я могу себе представить, что я не беру правильный подход к этой проблеме, но я нигде не могу найти некоторые советы или указатели для возможного решения.

ответ

58

Проблема заключается в том, что при использовании API на основе строк он не может вывести тип для результата результата get -Operation. Это объясняется, например, в Javadoc for Path.

Если вы используете

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

вместо этого, он будет работать нормально, потому что он может определить тип возвращаемого типа аргумента и выяснить, что она сопоставима. Обратите внимание, что использование вызова параметризованного метода root.<Date>get(...) (см., Например, When is a parameterized method call useful?).

Другое (на мой взгляд, лучшее) решение заключается в использовании API на основе метамодели вместо строкового. Простой пример канонической метамодели приведен, например, here. Если у вас больше времени на инвестиции, это хорошая статья о статической метамодели: Dynamic, typesafe queries in JPA 2.0

+1

NetBeans 8.2 по-прежнему предупреждает с помощью критериев. Я не знаю почему. 'builder.greaterThanOrEqualsTo (root.get (Some_.date), date)' <> 'builder.greaterThanOrEqualsTo (root. get (Some_.date), date)' –

+0

@Jin Kwon: Обязательно импортируйте 'javax.persistence .criteria.Predicate', а не 'java.util.function.Predicate'. Это исправило это для меня :) – Hank

+0

Неплохая проблема с импортом, это ошибка, очень старая. , вы должны объявить его как переменную и использовать его как параметр: 'Path path = root.get (.....); builder.greaterThan (путь, дата); ' – FiruzzZ

12

Вам необходимо использовать сгенерированную метамодель для доступа к атрибутам, это действительно безопасный способ. При использовании строк для обозначения ваших атрибутов, типы могут быть выведены только из явного общего типа, используемого при вызове метода, или типа броска, или с помощью автоматического вывода типа сделано компилятором:

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

Я получал аналогичную ошибку, но с синтаксисом predicates.add(cb.greaterThan(article.get(Article_.created), since)); и нашел эту страницу. Причиной для меня оказалось то, что я обновил свой проект с Java 1.7 до 1.8, и в этом процессе Maven также сконфигурировал компиляцию для Java 1.8. Мне просто пришлось сменить Maven на 1.7, сохранив остальную часть проекта на 1.8, чтобы исправить ошибку.

Смежные вопросы