Java Hibernate子查询问题

Java Hibernate子查询问题,java,hibernate,criteria,subquery,Java,Hibernate,Criteria,Subquery,我希望这应该是一个简单的问题 我有一张发票,发票上有一张付款清单 使用标准API,我试图返回发票列表及其付款总额。因此,在SQL中,我需要如下内容: SELECT i.*, (SELECT SUM(PMT_AMOUNT) FROM INVOICE_PAYMENTS p WHERE p.INVOICE = i.INVOICE) FROM INVOICES i 我一辈子都不知道如何使用CriteriaAPI实现这一点。做一些类似于: Criteria crit = session.createCr

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

我有一张发票,发票上有一张付款清单

使用标准API,我试图返回发票列表及其付款总额。因此,在SQL中,我需要如下内容:

SELECT i.*, (SELECT SUM(PMT_AMOUNT) FROM INVOICE_PAYMENTS p WHERE p.INVOICE = i.INVOICE) FROM INVOICES i
我一辈子都不知道如何使用CriteriaAPI实现这一点。做一些类似于:

Criteria crit = session.createCriteria(Invoice.class)
criteria.setProjection(Projections.projectionList()
          .add(Projections.sum("payements.paymentAmount").as("paymentTotal"))
select i, (select sum(p.amount) from InvoicePayments p where p.invoice = i.invoice) from Invoice i 
只需返回所有发票的预计付款总额的1行,这实际上是您所期望的,但这是我能得到的最接近的结果


非常感谢您的帮助。

我很确定您不能在投影中返回实体

有两种可能:

  • 运行两个条件查询,一个用于实际发票,另一个用于总计
  • 使用HQL执行查询
我还没有测试过这个,但应该是这样的:

Criteria crit = session.createCriteria(Invoice.class)
criteria.setProjection(Projections.projectionList()
          .add(Projections.sum("payements.paymentAmount").as("paymentTotal"))
select i, (select sum(p.amount) from InvoicePayments p where p.invoice = i.invoice) from Invoice i 

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

我很确定你不能返回投影中的实体

有两种可能:

  • 运行两个条件查询,一个用于实际发票,另一个用于总计
  • 使用HQL执行查询
我还没有测试过这个,但应该是这样的:

Criteria crit = session.createCriteria(Invoice.class)
criteria.setProjection(Projections.projectionList()
          .add(Projections.sum("payements.paymentAmount").as("paymentTotal"))
select i, (select sum(p.amount) from InvoicePayments p where p.invoice = i.invoice) from Invoice i 

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

有一种方法可以根据条件返回发票列表以及该发票的总付款

理论上,答案是您可以在投影查询上使用分组属性将结果分组为按发票支付的总金额。第二部分是,您可以在发票上使用暂时的“totalPayment”值,并使用转换器选择发票结构中的投影。这将比处理具有不同属性的ArrayList更容易,但这取决于您需要将结果用于什么

为了证明这一点,下面是小发票类的重要部分:

public class Invoice{
   private String name;

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

   // getters and setters
...
}

有一种方法可以使用条件返回发票列表以及该发票的总付款

理论上,答案是您可以在投影查询上使用分组属性将结果分组为按发票支付的总金额。第二部分是,您可以在发票上使用暂时的“totalPayment”值,并使用转换器选择发票结构中的投影。这将比处理具有不同属性的ArrayList更容易,但这取决于您需要将结果用于什么

为了证明这一点,下面是小发票类的重要部分:

public class Invoice{
   private String name;

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

   // getters and setters
...
}

您还可以在
总付款
字段中使用@Formula。缺点是,每次加载实体时都会计算“总和”。因此,您可以使用LAZY@Formula-do构建时增强或Pawel Kepka的技巧:缺点是,您有更多的LAZY@Fromula,您只命中其中一个,所有这些都被加载。另一个解决方案可能是使用@MappedSuperclass和更多子类。每个子类可能有不同的@Formula字段。在DB视图旁边还有一个解决方案:Hibernate@Subselect。

您还可以在
totalPayments
字段中使用@Formula。缺点是,每次加载实体时都会计算“总和”。因此,您可以使用LAZY@Formula-do构建时增强或Pawel Kepka的技巧:缺点是,您有更多的LAZY@Fromula,您只命中其中一个,所有这些都被加载。另一个解决方案可能是使用@MappedSuperclass和更多子类。每个子类可能有不同的@Formula字段。在DB view旁边还有一个解决方案:Hibernate@Subselect。

不幸的是,HQL在这里不是一个选项,而且我正在处理一个大数据集,因此运行两个查询也不理想。作为Hibernate原生sql查询来做是我能想到的唯一其他选项。试一试两个查询选项,您可能会对结果感到惊讶,db只在两个语句中而不是在一个语句中执行大致相同的工作,网络IO和解析的额外开销可能非常小。谢谢。实际上,我决定在oracle级别使用一个视图来解决这个问题,然后将该视图映射到一个对象。我尝试使用本机SQL查询,但它的性能根本不好,很可能是由于多次重复连接。事实证明,我的最终查询无论如何都相当复杂,即使是HQL也很难让它正常工作。不幸的是,HQL在这里不是一个选项,而且我正在处理一个大数据集,因此运行两个查询也不理想。作为hibernate本机sql查询来执行它大概是我能想到的唯一其他选项。试一试两个查询选项,您可能会对结果感到惊讶,db只在两个语句中而不是在一个语句中执行大致相同的工作,网络IO和解析的额外开销可能非常小。谢谢。实际上,我决定在oracle级别使用一个视图来解决这个问题,然后将该视图映射到一个对象。我尝试使用本机SQL查询,但它的性能根本不好,很可能是由于多次重复连接。事实证明,我的最终查询无论如何都相当复杂,即使是HQL也要尝试让它工作起来,这可能是一个挑战。