2011-12-15 2 views
1

내가 선택한 개체의 하위 컬렉션을로드하려고합니다. 나는 기본적으로 두 개의 미래의 질의를 생성 한 다음 그 중 하나를 열거하여이를 수행하는 것의 this way을 모방하려고하고있다. 이 경우 데이터베이스에 대한 두 개의 쿼리가 생성됩니다.Future 및 HQL의 도움을 받아 하위 컬렉션을로드하는 것을 열망합니다.

var idd = session.CreateQuery("from ItemDeliveryDetail idd " + 
           "join fetch idd.ItemDelivery " + 
           "left join fetch idd.SupplierInvoice " + 
           "where idd.Id = 21931828") 
       .Future<ItemDeliveryDetail>(); 

var spc = session.CreateQuery("from SpecialCondition spc " + 
           "where spc.ItemDelivery " + 
           "in (select idd.ItemDelivery " + 
            "from ItemDeliveryDetail idd " + 
            "where idd.Id = 21931828)") 
       .Future<SpecialCondition>(); 

var result = idd.ToList(); 

마지막 줄은 실제로 데이터베이스에 대한 두 개의 쿼리를 생성합니다. 쿼리는 정확히 내가 기대하는 것입니다 (오랜 시간이 걸리며 질문과 관련이 있다고 생각하지 않지만 보려는 경우 here).

foreach (var itemDeliveryDetail in result) 
{ 
    foreach (var specialCondition in itemDeliveryDetail.ItemDelivery 
                 .SpecialConditions) 
    { 
     // Do something 
    } 
} 

어떻게 그 문제를 해결하기 위해 :

문제는 두 쿼리의 결과 즉, 다음 열거 여전히 ItemDelivery 각각의 SpecialCondition들에 대한 데이터베이스를 조회합니다, 결합되지인가?

+0

3 개의 검색어가 필요하지 않습니까? 하나는 ItemDeliveryDetail, 하나는 ItemDelivery, 다른 하나는 SpecialConditions를 얻으려고합니까? – MerickOWA

+0

'ItemDeliveryDetail' 쿼리에서'ItemDelivery'를 열심히 가져 오기 때문에 나는 그렇게 생각하지 않습니다. –

+0

@MerickOWA : 그러나 확실히, 나는 그것을 시험해 보았습니다. 그리고 그것은 정말로 아무것도 변화시키지 않았습니다. –

답변

1

두 번째 쿼리는 이 아니며ItemDelivery.SpecialConditions 콜렉션을로드합니다. SpecialConditions의 사용되지 않는 목록 만.

나는 Rippo에 동의합니다. batch-size을 사용하면 이 더 깨끗하고 성능이 뛰어납니다. 단 하나 또는 두 번 이상의 왕복이 발생하더라도입니다. 말했다

, 두 번째 질의는해야한다 :

var spc = session.CreateQuery("from ItemDelivery id " + 
           "join fetch id.SpecialCondition " 
           "where id in (select idd.ItemDelivery " + 
              "from ItemDeliveryDetail idd " + 
              "where idd.Id = 21931828)" 
      .Future<ItemDelivery>(); 
+0

이것은'Future '을'Future '로 변경 한 경우에만 작동합니다. 그러나 그것은 내가 필요한 것입니다. –

+0

고정 유형 매개 변수입니다. –

1

하나의 빠른 승리는 batch-size=50을 가방 매핑에 ItemDeliverySpecialConditions 사이에 추가하는 것입니다.

그러나 나는 당신이 찾고있는 대답을 당신에게 줄지도 모르는 Ayende의이 블로그 " Eagerly loading entity associations efficiently with NHibernate"을 읽는 것이 좋습니다.

여기에서 고전적인 선택 n + 1 문제에 직면 해 있습니다. 오히려 큰 cartesian product 결과 집합보다는 오히려 데이터베이스에 1 또는 2 개의 더 많은 여행을 가지고 싶습니다. 나는 이것이 가장 영향력있는 길일 것이라고 확신한다.

+0

답변 해 주셔서 감사합니다. 그러나, 그것은 약간 벗어났다. 나는 여기서 N + 1 문제에 직면하고 있음을 안다. 사실, 내 코드에서'Future'를 사용하는 유일한 목적은 그것을 피하는 것입니다. 당신이 제안하고있는 블로그 게시물은 내 질문에 이미 링크 된 게시물입니다. 나는 또한'batch-size = 50'이 내가 가지고있는 문제를 해결하지 못한다고 확신한다.간단히 말해서, N이 반환 된 행과 독립적 인 모든 필요한 데이터를 반환하는 N 개의 쿼리를 선행하게하고 싶습니다. 현재 두 개의 쿼리 (N = 2)가 있는데, 하나는'ItemDeliveryDetail'이고 다른 하나는'SpecialCondition'입니다. –

+0

블로그 게시물에 대해 죄송합니다. 그러나'batch-size'를 설정하는 것이'parent-> children-> grandchildren'의 거대한 cartessian 결과를 갖는 것보다 가장 수행 가능성이 높습니다 – Rippo

+0

문제는 반환 된 모든 데이터가 필요하므로 생각하지 않습니다. 배치 크기를 설정하는 것이 좋습니다. 아니면 배치 크기가 잘못되었다는 것을 알고 있습니까? –

0

당신은 내가 당신의 문제라고 생각하는 두 번 같은 기본 쿼리를 사용해야합니다.

var idd = session.CreateQuery("from ItemDeliveryDetail idd " + 
          "join fetch idd.ItemDelivery " + 
          "left join fetch idd.SupplierInvoice " + 
          "where idd.Id = 21931828") 
      .Future<ItemDeliveryDetail>(); 

var spc = session.CreateQuery("from ItemDeliveryDetail idd " + 
          "join fetch idd.ItemDelivery id " + 
          "join fetch id.SpecialCondition spc " + 
         "where idd.Id = 21931828") 
      .Future<ItemDeliveryDetail>(); 

var result = idd.ToList(); 

예이 현상은 사용자를 위해 데카르트 제품을 유발할 수 있음을 알고 있지만이 기술을 사용하여 성공했습니다.

+0

이 방법은'SupplierInvoice'가'ItemDeliveryDetail'에서'SupplierInvoice'까지 다 대다, 즉 모든'ItemDeliveryDetail'만이 하나의'SupplierInvoice'를 가지기 때문에 단일 쿼리를 사용하는 것보다 더 단순화 될 수 있습니다. 두 개의 쿼리는 방금 설명한 하나의 쿼리에 비해 장점이 없습니다. 그리고 그 거대한 데카르트 제품이 내가 처음에 하나의 쿼리를 사용하지 않은 이유입니다 ... –

관련 문제