7

これは、here (EF 4.1 code-first: How to load related data (parent-child-grandchild)?)の質問の第2ステップです。 @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(); 
      } 
     } 

:私の最初のコードは、このでした。 (例えば最初のコード上記のように)今

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

、どのように私は注文することができ、子供(孫)、それらを選択:@Slaumaの指導によって、私はこの1つのクエリを変更する(上記のリンク上で説明しましたか)?

+1

この質問をご覧ください:http://stackoverflow.com/questions/4156949/ef4-linq-ordering-parent-and-all-child-collections-with-eager-loading-includeあなたがしようとしているのは "熱心な読み込み"です。明らかに、 'OrderBy'を' Include'で使うことはできません。 – devuxer

+0

はい、私は熱心な読み込みについて知っています。最初のコード(自分で作成したもの)を見ると、各レベルの各オブジェクトにforeachステートメントが使用されていることがわかります(子供の場合は先頭、孫の場合は子供)準備されたリンクについて説明したように。これはデータベースに対してより多くのクエリを必要とします!私はこれをすべて1つのクエリで行う方法を探しています。 –

+0

構造全体を読み込み、必要なときにビューで注文することができますか?データアクセスロジックでプレゼンテーションロジック(順序付け)を漏らす必要がある理由はほとんどありません。 –

答えて

22

残念ながら、積極的なロード(Include)がロードされたのいずれかのフィルタリングやソートをサポートしていません。子コレクション

  • Expliciteソートされた読み込みを使用してデータベースに複数回ラウンドトリップします。それはあなたの質問の最初のコードスニペットです。複数回のラウンドトリップは必ずしも悪いことではなく、IncludeとネストされたIncludecan lead to huge multiplication of transfered data between database and clientです。

  • Include又はInclude(....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に対して送られた1つのクエリ(^_^)特別なおかげです。私はちょうど '.Select(c => new { 親= c、 子= c.Children。 OrderBy(cc => cc.Order) }}')で内側の 'Select 'を変更しました。何度も何度もありがとう。 –

+1

@ChrisMoschini: 'ProxyCreationEnabled'は重要ですか?私はほとんど変更トラッキングプロキシを使用しておらず、関係スパンはまだ動作しています。 – Slauma

+0

@Slaumaあなたは正しいです!プロキシを無効にして、この種のプロジェクションを実行できない高速の読み取り専用クエリに対しては、追跡機能を使用しないコードがあります。プロキシを無効にしてもうまくいけば、それはレンチをスローするAsNoTracking()だけです。 –

0

あなたにお試しください。

... セレクト(c.children orderbyのch.property desending 中のCHからCHを選択) ...

+0

動作しません!エラーは次のとおりです。*インクルードパス式は、そのタイプで定義されたナビゲーションプロパティを参照する必要があります。参照ナビゲーションプロパティには点線のパスを使用し、コレクションナビゲーションプロパティにはSelect演算子を使用します。 パラメータ名:パス* –

関連する問題