2011-12-15 78 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)。

問題是,這兩個查詢的結果沒有被組合,即下面列舉仍然將查詢的SpecialCondition s分別ItemDelivery的數據庫:

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

如何解決呢?

+0

你不需要3個查詢嗎?一個獲得ItemDeliveryDetail,一個獲得ItemDelivery,一個獲得SpecialConditions? – MerickOWA 2011-12-15 16:07:53

+0

我不這麼認爲,因爲我急於在ItemDeliveryDetail查詢中獲取ItemDelivery。 – 2011-12-15 16:18:38

+0

@MerickOWA:但可以肯定的是,我只是對它進行了測試 - 它確實不會改變任何事情。 – 2011-12-15 16:42:29

回答

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>(); 
1

一次快速獲勝可能是將batch-size=50添加到ItemDeliverySpecialConditions之間的包映射。

但是,我建議你閱讀Ayende的這篇博文「 Eagerly loading entity associations efficiently with NHibernate」,因爲它可能會爲你提供你正在尋找的答案。

您正面臨經典的選擇n + 1問題。我寧願有1或2次更多的數據庫訪問,而不是一個大的cartesian product結果集。我相信這將是最高效的路線。

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(); 

是的我意識到這可能會導致你的笛卡爾產品,但我已經使用這種技術取得了很好的成功。