2017-04-12 1 views
0

データを入力するのにうまく動作するEF 6とMVC 5を使用するアプリがありますが、その一部を表示しようとすると問題が発生します。私のエンティティの基本的なレイアウトは、次の図で見ることができます。EF 6とMVC 5の子データと孫データを照会して表示するにはどうすればよいですか?

entity layout

私は悩みを抱えている最初の部分は、データを照会し、フィルタリングです。私は調査とサインオフが存在するが、承認はしていないが、施設や関係するデータのリストを返すことを望む。ストレートSQLでは、動作するようになりましたクエリは次のとおりです。

SELECT * 
FROM Premises p LEFT OUTER JOIN Approvals a ON a.Id = p.Id 
JOIN Surveys s ON s.PremiseId = p.Id 
JOIN SignOffs so ON so.Id = s.Id 
WHERE a.ApprovedBy IS NULL 

私が始めたコードは次のようである:

var premises = Premises.Include(p => p.Approval) 
    .Include(p => p.Surveys) 
    .Include(p => p.Surveys.Select(s => s.SignOff)); 

これは、は*子データを含むすべてのレコードを返すように見えますが、それをフィルタリングしようとするとサインオフレコードを持つレコードだけが取得されますが、承認されていないレコードは取得できません。

var premises = Premises.Include(p => p.Approval).Where(p => p.Approval.ApprovedBy == null) 
    .Include(p => p.Surveys) 
    .Include(p => p.Surveys.Select(s => s.SignOff).Where(s => s.Signature != null)); 

私はこのコードを使用している場合は、私はこのエラーを取得:

パス式はタイプに定義されたナビゲーションプロパティを参照する必要があります含めます。参照ナビゲーションプロパティには点線のパスを使用し、コレクションナビゲーションプロパティにはSelect演算子を使用します。 パラメータ名:パス

私は別のものを試して、多くの周りにこのクエリを変更したので、私は私がやっていることすべてのわからないんだけど、私は最初のWhere文は、それ自体でうまくいくかもしれないと思うが、 2番目のエラーは間違いなく発生します。 要求されたデータを正しくフィルタリングして返すようにクエリを構造化する必要はありますか?

また、実際にテストできないため、と表示され、すべてのデータと子データが返されると述べています。このために私のRazor CSHTMLページを書いてみると、子供や孫のデータを知ることはできません。もし私が何を入力すればエラーになるのでしょうか?このデータをページ上でどのように参照する必要がありますか?

答えて

1

このようにを使用することはできません。ナビゲーションプロパティをロードするように指定するだけで、ナビゲーションプロパティが何かの場合にエンティティをロードするよう指定することはできません。フィルタリングを行うには

、私はこのような何かお勧め:

var premises = Premises.Include(p => p.Approval).Include(p => p.Surveys).Include(p => p.Surveys.Select(s => s.SignOff)) 
       .Where(p=>p.Approval.ApprovedBy!=null && p.Surveys.Any(s=>s.SignOff.Signature!=null)); 

をので、基本的には含まれており、フィルタリングはお互いに何の関係もありません。インクルードでは、ロードするものだけを指定しますが、元のエンティティセットでフィルタを使用することはできます。

1

Include LINQメソッドが何をしているのか混乱しています。その関係を熱心に読み込むようEFに指示しますが、クエリ自体がその関係を利用する場合は実際には不要です。その場合、EFはデフォルトで関係を含めます。

これらの関係をフィルタリングすることはできません。たとえば、あなたのコードのこの部分で:句がPremisesに適用される

.Include(p => p.Surveys.Select(s => s.SignOff).Where(s => s.Signature != null)); 

ザ・、ないSignOffはあなたが考えているようだと。つまり、Whereは、照会されているメインテーブルをフィルタリングし、含まれているテーブルはフィルタリングしません。

ここには2つの経路があります。あなたは、単に重要な部分、すなわちによってPremisesをフィルタリングすることができます。これらの条件に該当するのみ施設を返しますが、含まSurveysコレクションは、各前提に関連すべて調査を、ないものだけが含まれます

var premises = Premises.Where(p => p.Approval.ApprovedBy == null && p => p.Surveys.Any(s => s.SignOff.Signature != null)); 

サインオフ署名はヌルです。そのためどのようにこのクエリ必見の性質の

  1. あなたは、あなたがそれらを明示的にロードする必要があり、同様に関連するアイテムをフィルタリングする必要がある場合:

    foreach (premise in premises) 
    { 
        context.Entry(premise) 
         .Collection(p => p.Surveys) 
         .Query() 
         .Where(s => s.SignOff.Signature != null) 
         .Load(); 
    } 
    

    ノートの2つのこと適用されると、すべての施設のためにそれを一度行う方法はありません。あなたは敷地内を反復して、明示的にそれぞれSurveysコレクションをロードする必要があります。

  2. これは新しいクエリーを発行するので、このExplicitロードの前にSurveysコレクションを遅延または慎重にロードしないようにします。それ以外の場合は、同じ情報を2回クエリしているため、非常に非効率です。これを確実に行う最も簡単な方法は、virtualキーワードをコレクションプロパティから削除することです。しかし、そうすると、コレクションを熱心に、または明示的にロードする必要があります。そうしないと、コレクションはnullになります。詳細は、https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx

を参照してください。
関連する問題