7

這是解釋爲here (EF 4.1 code-first: How to load related data (parent-child-grandchild)?)的問題的第二步。 按@Slauma的指導我可以檢索數據。我的第一個代碼是這樣的:EF 4.1代碼優先:如何在使用包含和/或選擇方法時訂購導航屬性?

 var model = DbContext.SitePages 
      .Where(p => p.ParentId == null && p.Level == 1) 
      .OrderBy(p => p.Order) // ordering parent 
      .ToList(); 
     foreach (var child in model) { // loading children 
      DbContext.Entry(child) 
       .Collection(t => t.Children) 
       .Query() 
       .OrderBy(t => t.Order) // ordering children 
       .Load(); 
      foreach (var grand in child.Children) { // loading grandchildren 
       DbContext.Entry(grand) 
       .Collection(t => t.Children) 
       .Query() 
       .OrderBy(t => t.Order) // ordering grandchildren 
       .Load(); 
      } 
     } 

它的工作原理,但是,這將發出許多查詢針對數據庫和我正在尋找一種方式來做到這一切在短短的一個查詢。通過@Slauma的指導意見(上面的鏈接解釋)我更改查詢到這一個:選擇時,他們

 var model2 = DbContext.SitePages 
      .Where(p => p.ParentId == null && p.Level == 1) 
      .OrderBy(p => p.Order) 
      .Include(p => p.Children // Children: how to order theme??? 
       .Select(c => c.Children) // Grandchildren: how to order them??? 
      ).ToList(); 

現在,我怎麼可以爲了孩子(和孫子)(如第一碼以上)?

+1

看看這個問題:http://stackoverflow.com/questions/4156949/ef4-linq-ordering-parent-and-all-child-collections-with-eager-loading-include。你所要做的就是「急切加載」,顯然,你不能在'Include'中使用'OrderBy'。 – devuxer

+0

是的,我知道急切的加載,如果你看第一個代碼(由我自己創建),你會看到我在每個級別的每個對象上使用一個foreach語句(頂級爲子級,子級爲孫級)正如你準備好的鏈接所解釋的那樣。但是這需要對數據庫進行更多的查詢!我正在尋找一種方法在一個查詢中完成所有操作,而不是更多! –

+0

您是否可以急於加載整個結構,然後在需要時在視圖中進行排序?在你的數據訪問邏輯中,你應該泄露表示邏輯(排序)幾乎沒有理由。 –

回答

22

不幸的是預先加載(Include)不支持任何過濾或加載排序兒童收藏。有三種選擇可以實現你想要的功能:

  • 多次往返數據庫並進行明確的排序加載。這是你問題中的第一個代碼片段。請注意,多次往返不一定是壞的,並且Include和嵌套Includecan lead to huge multiplication of transfered data between database and client

  • 使用預先加載與IncludeInclude(....Select(....))和排序內存中的數據被載入後:

    var model2 = DbContext.SitePages 
        .Where(p => p.ParentId == null && p.Level == 1) 
        .OrderBy(p => p.Order) 
        .Include(p => p.Children.Select(c => c.Children)) 
        .ToList(); 
    
    foreach (var parent in model2) 
    { 
        parent.Children = parent.Children.OrderBy(c => c.Order).ToList(); 
        foreach (var child in parent.Children) 
         child.Children = child.Children.OrderBy(cc => cc.Order).ToList(); 
    } 
    
  • 使用的投影:

    var model2 = DbContext.SitePages 
        .Where(p => p.ParentId == null && p.Level == 1) 
        .OrderBy(p => p.Order) 
        .Select(p => new 
        { 
         Parent = p, 
         Children = p.Children.OrderBy(c => c.Order) 
          .Select(c => new 
          { 
           Child = c, 
           Children = c.Children.OrderBy(cc => cc.Order) 
          }) 
        }) 
        .ToList() // don't remove that! 
        .Select(a => a.Parent) 
        .ToList(); 
    

這只是一個單一的往返和工作,如果你不禁止更改跟蹤(不要在此查詢中使用.AsNoTracking())。此投影中的所有對象都必須加載到上下文中(爲什麼需要第一個ToList()),上下文將正確地將導航屬性綁定在一起(這是一個名爲「關係範圍」)的功能。

+0

OMG特別感謝Slauma!做得好做得很好:D:D:D這是有效的,我跟蹤它,只是一個查詢發送反對db (^_^)特別感謝親愛的。我只是用'.Select(c =>新的父親= c, Children = c.Children。 OrderBy(cc => cc.Order) }}''改變了內部的'選擇'。再次感謝。 –

+1

@ChrisMoschini:你確定'ProxyCreationEnabled'很重要嗎?我幾乎從不使用更改跟蹤代理,並且關係跨度仍然有效。 – Slauma

+0

@Slauma你是對的!我們的代碼使用代理禁用和不跟蹤快速只讀查詢無法做這種投影;但代理禁用就好了,它只是AsNoTracking()引發了一個扳手。 –

0

你有試過嗎?

... 選擇(從c.children CH 排序依據ch.property desending 選擇CH) ...

+0

不起作用!錯誤是*包含路徑表達式必須引用在類型上定義的導航屬性。對於參考導航屬性使用虛線路徑,對集合導航屬性使用Select運算符。 參數名稱:路徑* –

相關問題