2012-03-29 69 views
6

任何人都可以帮助我获得下面提到的JPA查询的JPA标准查询。如何使用JPA Criteria查询编写此查询?

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

你可以显示你的人员和语言的实现吗? – 2012-03-29 14:20:43

回答

10

假设人有关系的语言这里就是你会在较老的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调用。

+4

限制不是JPA规范的一部分,它是休眠功能 – perissf 2012-03-29 14:58:56

+0

您是对的,我需要翻译为JPA 2 – 2012-03-29 15:10:13

+0

嘿,首先感谢,我应该把它放在这个问题上。 有没有**关系** b/w实体的人和语言。人员和语言都有一个共同的列(语言(varchar)),我将加入该列。对我造成的问题是,我需要做一个** LEFT OUTER JOIN **,这样如果没有可用于该人的语言数据,我仍然应该能够将语言对象的人员数据作为空值。 – user1300877 2012-03-29 18:21:08

6

尽管johncarl给出的答案已被接受,但它对我来说并不正确。对于CriteriaQuery.where()的Javadoc说:

修改查询根据 指定布尔表达式来限制查询结果。替换之前添加的 限制(若有)。

据我了解,以下各行(给予限制)将覆盖前面给出的限制:

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

这意味着,在年底开始和结束日期之间只有最后一个限制( )将保持。

我threfore提出以下修改johncarl的回答是:

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

但是,此代码看起来真难看!请随时编辑,如果它是错误的,并评论它,如果你看到更好的解决方案!我会很优雅!

+0

非常感谢您的提示。其中(...)不能逐渐使用,因为它完全替代了可能通过的标准。另一方面,builder.and和(“where谓词的数组”)工作的单个问题。很棒的解决方案,pho312 :) – Hartmut 2015-09-18 19:05:31

+0

谢谢你的提示!我完全喜欢你的方法。我只是简单地补充说一个人可以创建一个ArrayList,并在他们出现时简单地添加标准。另一方面,我不知道为什么,但pRoot.get(Person_.name)不适用于我。 Anume我用Person_语法得到一个错误。 – moldovean 2016-11-11 13:30:58