Hibernate子查询问题

时间:2009-10-14 19:38:10

标签: java hibernate criteria subquery

这应该是一个我希望的简单。

我有发票,发票上有付款清单。

使用Criteria API我正在尝试返回发票及其付款总额列表。所以,在SQL中我想要这样的东西:

SELECT i.*, (SELECT SUM(PMT_AMOUNT) FROM INVOICE_PAYMENTS p WHERE p.INVOICE = i.INVOICE) FROM INVOICES i

我不能为我的生活弄清楚如何使用Criteria API实现这一目标。做类似的事情:

Criteria crit = session.createCriteria(Invoice.class)
criteria.setProjection(Projections.projectionList()
          .add(Projections.sum("payements.paymentAmount").as("paymentTotal"))

简单地返回1行,其中包含所有发票的预计付款总额,这实际上是您所期望的,但这是我能够得到的。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:3)

有一种方法可以让Criteria返回发票清单以及该发票的总付款。

理论上,答案是您可以在投影查询中使用分组属性,将结果分组为发票总付款。第二部分是您可以在Invoice上使用瞬态“totalPayment”值,并使用变换器选择投影到Invoice结构中。这比处理不同属性的ArrayList更容易,但取决于你需要使用的结果。

为了证明这一点,以下是小型Invoice类的重要部分:

public class Invoice{
   private String name;

   @Transient private int totalPayments;
   @OneToMany Set<Payment> payments = new HashSet<Payment>();

   // getters and setters
...
}

然后这是您可以使用的标准

Criteria criteria = session.createCriteria(Invoice.class)
            .createAlias("payments", "pay")
            .setProjection(Projections.projectionList()
                .add(Projections.groupProperty("id"))
                .add(Projections.property("id"), "id")
                .add(Projections.property("name"), "name")
                .add(Projections.sum("pay.total").as("totalPayments")))
            .setResultTransformer(Transformers.aliasToBean(Invoice.class));

List<Invoice> projected = criteria.list();

这是生成的SQL

Hibernate: 
   select this_.id as y0_, 
          this_.id as y1_, 
          this_.name as y2_, 
          sum(pay1_.total) as y3_ 
   from invoice this_ 
   inner join invoice_payment payments3_ on this_.id=payments3_.invoice_id 
   inner join payment pay1_ on payments3_.payments_id=pay1_.id 
   group by this_.id

答案 1 :(得分:1)

我很确定你无法在投影中返回实体。

有两种可能:

  • 运行两个条件查询,一个用于实际发票,另一个用于总计
  • 使用HQL执行查询

我没有测试过这个,但它应该是这样的:

select i, (select sum(p.amount) from InvoicePayments p where p.invoice = i.invoice) from Invoice i 

将要等到明天,我有一个非常相似的数据结构在工作我应该能够测试它。

答案 2 :(得分:1)

您还可以将@Formula用于totalPayments字段。缺点是,每次加载实体时都会计算“总和”。所以,你可以使用LAZY @Formula - 建立时间增强或Pawel Kepka的诀窍:http://justonjava.blogspot.com/2010/09/lazy-one-to-one-and-one-to-many.html缺点是,你有更多的LAZY @Fromula而你只打了其中一个,所有这些都被加载了。另一种解决方案可能是使用@MappedSuperclass和更多子类。每个子类可能具有不同的@Formula字段。在DB视图旁边还有一个解决方案:Hibernate @Subselect。