2013-01-20 60 views
3

我有两个实体Customer和Order以一对多的关系。 对于每位客户,我需要统计相关订单的数量并按照该数字对结果进行排序。 在本地Postgres的查询它看起来像这样:JPA CriteriaBuilder - 根据一对多关系中关联实体的数量排序

select cust.id, count(order.id) from customers cust 
left outer join orders order 
on cust.id = order.customer_id 
where .... conditions ... 
group by cust.id 
order by count desc; 

但由于该查询是使用CriteriaBuilder摆在附加条件一块较大的代码的一部分,我必须做到这一点使用CriteriaBuilder。在Hibernate中,我可能会使用Projections,但在JPA中找不到类似的东西。

任何使用CriteraBuilder编写查询的帮助将不胜感激。

预先感谢您。

+0

看看一个很好的教程。我个人建议[这一个](http://www.ibm.com/developerworks/java/library/j-typesafejpa/) – perissf

回答

6

假设实体客户有OneToMany属性是这样的:

@OneToMany(mappedBy = "customerId") 
private Collection<Order> orders; 

您可以使用下面的查询:

EntityManager em; // to be built or injected 
CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Tuple> cq = cb.createTupleQuery(); 
Root<Customer> customer = cq.from(Customer.class); 
CollectionJoin<Customer, Order> orders = customer.join(Customer_.orders, JoinType.LEFT); 
cq.select(cb.tuple(customer, cb.count(orders))); 
cq.where(... add some predicates here ...); 
cq.groupBy(customer.get(Customer_.id)); 
cq.orderBy(cb.desc(cb.count(orders))); 
List<Tuple> result = em.createQuery(cq).getResultList(); 
for (Tuple t : result) { 
    Customer c = (Customer) t.get(0); 
    Long cnt = (Long) t.get(1); 
    System.out.println("Customer " + c.getName() + " has " + cnt + " orders"); 
} 

上述方法使用Metamodel。如果您不喜欢它,您可以用"orders"Customer_.id替换Customer_.orders"id"

如果OneToMany属性是另一种类型的,用适当的类型(ListJoinSetJoinMapJoin)的集合取代CollectionJoin

+0

谢谢你的答案。不幸的是,它并不适用于我的情况 - 原因是我试图整合我的代码是如此的结构化,以至于它使用'SimpleJpaRepository'中的'findAll(规范 spec,Pageable pageable)' - 传入'Pageable'对象也必须包含按列排序。如果我没有指定在[PageRequest(int page,int size,Sort sort)中进行排序的列,但是通过CriteariaBuilder按照上面的建议进行排序 - 它只是假定排序为空并覆盖了我指定的任何顺序在CriteriaBuilder中。 – Alex

+0

我不明白,你能澄清吗?然而这似乎是一个完全不同的问题。我建议打开一个新的标记,如果它回答了原来的问题,这看起来确实如此。 – perissf

+0

这发生在'SimpleJpaRepository',第417行:'query.orderBy(toOrders(pageable.getSort(),root,builder));'。我正在检查Spring数据源以找到一种方法来使它与Pageable协同工作,并且不会覆盖我在CriteriaBuilder中指定的顺序。如果你能够进一步提醒我,我会非常感激。虽然我知道你已经帮了我很多。谢谢。 – Alex