2009-10-14 6 views
1

이것은 간단한 것이어야합니다.최대 절전 모드 하위 쿼리 질문

송장이 있으며 그 송장에는 지불 목록이 있습니다.

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 개 행을 반환하지만 이것이 내가 얻을 수있는 가까운 거리

.

도움을 주시면 대단히 감사하겠습니다.

답변

1

저는 프로젝션에서 엔티티를 반환 할 수 없다고 확신합니다. 내가 테스트하지 않았습니다

쿼리를 수행 할

  • 사용 HQL이 합계에 대한

    • 실행 두 가지 기준 쿼리, 실제 송장 하나 하나

      두 possibles있다 하지만 다음과 같이되어야합니다.

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

      Tomorro가 대기해야합니다. w, 나는이 작업을 테스트 할 수 있어야하는 작업에서 매우 유사한 데이터 구조를 가지고 있습니다.

  • +0

    불행히도 HQL은 여기서는 옵션이 아니며 큰 데이터 세트로 작업하므로 두 개의 쿼리를 실행하는 것이 이상적이지 않습니다. –

    +0

    최대 절전 모드 네이티브 SQL 쿼리로 수행하는 것은 내가 생각할 수있는 유일한 다른 옵션에 관한 것입니다. 두 가지 쿼리 옵션을 사용하면 결과에 놀랄 수 있습니다. db는 단일 명령이 아니라 두 명령문에서 거의 동일한 작업을 수행합니다. 네트워크 IO 및 구문 분석의 추가 오버 헤드는 매우 작을 수 있습니다. –

    +0

    감사합니다. 필자는 실제로 오라클 수준의 뷰를 사용하여이 문제를 해결하기로 결정한 다음 해당 뷰를 객체에 매핑했습니다. 네이티브 SQL 쿼리를 사용해 보았지만 성능이 좋지 않았습니다. 대부분의 반복 된 조인 때문에 발생했을 가능성이 큽니다. 결국 내 최종 쿼리가 다소 복잡해졌으며 심지어 HQL을 통해 작동 시키려고 시도하는 것이 어려웠을 수도 있습니다. –

    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

    또한 totalPayments 필드 @Formula를 사용할 수 있습니다. 단점은 엔터티를로드 할 때마다 "합계"가 계산된다는 것입니다. 따라서 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.