2009-10-14 3 views
1

Надеюсь, это будет простой.Hibernate Subquery Вопрос

У меня есть счет-фактура, и у счета есть список платежей.

Использование 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 строку с прогнозируемым платежа общей для всех счетов-фактур, которые на самом деле то, что вы ожидали бы, но это так близко, как я могу получить.

Любая помощь очень ценится.

ответ

1

Я уверен, что вы не можете вернуть объекты в проекции.

Есть два:-плюс

  • Выполнить два критерий запросов, один для реальных счетов и один для там составляет
  • Используйте HQL для выполнения запроса

Я не проверял это должно выглядеть примерно так:

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

Придется подождать до tomorro w, у меня очень похожая структура данных на работе, я должен быть в состоянии проверить это.

+0

К сожалению, HQL здесь не вариант, и я работаю с большим набором данных, поэтому запуск двух запросов тоже не идеален. – 2009-10-14 20:28:58

+0

делать это как спящий родной sql-запрос - это единственный вариант, о котором я могу думать. Дайте два варианта запроса, вы можете быть удивлены результатом, db будет делать примерно ту же работу только в двух операциях, а не в одном, дополнительные накладные расходы на сетевом IO и синтаксический анализ могут быть довольно маленькими. –

+0

Спасибо. Я на самом деле решил решить это, используя представление на уровне оракула, а затем просто сопоставил это представление с объектом. Я попытался использовать собственный SQL-запрос, но он не работал хорошо, скорее всего, из-за многочисленных повторных подключений. Оказывается, мой окончательный запрос был довольно сложным в любом случае, и попытка заставить его работать даже через HQL, возможно, была сложной задачей. – 2009-10-15 17:02:49

3

Существует способ с критериями для возврата списка счетов-фактур вместе с общими платежами для этого счета-фактуры.

Теоретически, ответ заключается в том, что вы можете использовать свойство группировки в запросе проекции для группировки результата в общий платеж по счету. Вторая часть состоит в том, что вы можете использовать переходное значение «totalPayment» в счете-фактуре и выбрать проекцию в структуру счета-фактуры с использованием трансформатора. Это было бы легче, чем иметь дело с ArrayList разных свойств, но будет зависеть от того, что вам нужно для использования результатов.

Чтобы продемонстрировать это, здесь является важной частью малого класса счетов:

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

Вы также можете использовать @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.

Смежные вопросы