Как написать этот запрос, используя запрос JPA Criteria? - PullRequest
6 голосов
/ 29 марта 2012

Может ли кто-нибудь помочь мне получить запрос критерия JPA для запроса JPA, упомянутого ниже.

SELECT p,l FROM Person p 
LEFT JOIN Language l ON (p.language = l.language and l.locale like :locale) 
AND p.name like :name 
AND p.time BETWEEN :startDate 
AND :endDate order by name asc

Ответы [ 2 ]

13 голосов
/ 29 марта 2012

Если предположить, что Person имеет отношение к языку, то, что вы будете делать в старом Hibernate:

Criteria criteria = entityManager.createCriteria(Person.class);
Criteria languageCriteria = criteria.createCriteria("language");

languageCriteria.add(Restrictions.like("locale", locale));

criteria.add(Restrictions.like("name", name));
criteria.add(Restrictions.between("time", startDate, endDate));

criteria.addOrder(Order.asc("name"));

и моя первая попытка JPA 2.0:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createCriteria(Person.class);
Root<Person> pRoot = criteria.from(Person.class);
Join<Person, Language> langJoin = criteria.join("language", JoinType.LEFT);

Predicate conjunction = builder.conjunction();

criteria.where(builder.and(
    builder.like(langJoin.get(Language_.locale), locale),
    builder.like(pRoot.get(Person_.name), name),
    builder.between(pRoot.get(Person_.time), startDate, endDate));

criteria.orderBy(builder.asc(pRoot.get(Person_.name)));

Пожалуйста, дайте мне знатьесли это работает для вас.

Редактировать: Обновлен запрос для использования только одного where вызова.

7 голосов
/ 25 марта 2015

Хотя ответ, данный Джонкарлом, был принят, он не выглядит правильным для меня.JavaDocs для CriteriaQuery.where () говорят:

Измените запрос, чтобы ограничить результат запроса в соответствии с указанным логическим выражением.Заменяет ранее добавленные ограничения, если таковые имеются.

Насколько я понимаю, каждая из следующих строк (с указанием ограничений) будет отменять ограничения, данные ранее:

criteria.where(builder.like(langJoin.get(Language_.locale), locale));
criteria.where(builder.like(pRoot.get(Person_.name), name));
criteria.where(builder.between(pRoot.get(Person_.time), startDate, endDate));

Это означает, что в конце останется только последнее ограничение (между начальной и конечной датой).

Поэтому я предлагаю следующие модификации ответа Джонарла:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createCriteria(Person.class);
Root<Person> pRoot = criteria.from(Person.class);
Join<Person, Language> langJoin = criteria.join("language", JoinType.LEFT);

Predicate[] restrictions = new Predicate[] { 
    builder.like(langJoin.get(Language_.locale), locale),
    builder.like(pRoot.get(Person_.name), name),
    builder.between(pRoot.get(Person_.time), startDate, endDate)
};

criteria.where(builder.and(restrictions));

criteria.orderBy(builder.asc(pRoot.get(Person_.name)));

Однако этот код выглядит действительно безобразно!Пожалуйста, не стесняйтесь редактировать, если это не так, и комментируйте, если вы видите лучшее решение!Я был бы изящен!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...