2016-01-06 15 views
6

私は以下を参照してください、両方が潜在的にnullになる可能性があり、プロパティとして二つのオブジェクト(UserPrimaryNode)を持つオブジェクトを持っている:Entity FrameworkのObjectQuery.Include()

public class Item 
{ 
    [Key] 
    public int ItemId { get; set; } 
    public string ItemName { get; set; } 
    public Node PrimaryNode { get; set; } 
    public User User { get; set; } 
} 

私は移入するEntity Frameworkの6を使用していますItemオブジェクトを使用し、連鎖インクルードを使用して、PrimaryNodeおよびUserオブジェクトをその中に移入します。

using (var db = new MyContext()) 
{ 
    var item = db.Items.Include(i => i.User).Include(n => n.PrimaryNode).FirstOrDefault(i => i.ItemId == id); 
} 

上記の例では、i.Useritem変数がヌルであるNULLの場合:

最初の連鎖、ヌルのようにオブジェクト全体戻るヌルを目的としている例が挙げられます。サブオブジェクトがnullの場合、親オブジェクトと他のサブオブジェクトにはまだポピュレートされるように、両方のサブオブジェクトにデータを取り込む最良の方法はありますか?

+3

'PrimaryNode'と' User'仮想を作成し、オプションとして 'Item'にマップしますか? –

+0

私は@octaviocclのステートメントに同意します - あなたの質問に間違いはありません。私のテストでは、UserオブジェクトがItemにリンクされていなくても、そのクエリはNodeオブジェクトに値を設定します。 –

+0

私は上記のアプローチに間違いがないことを確認できるようになりました。複雑なクラスであったものを単純化しました。私の場合の問題は、Userオブジェクトを持つだけでなく、UserIdプロパティも持っていたことです(私はいくつかのサークルで推奨されているように、UserオブジェクトをロードすることなくIDを取得できます)。問題を引き起こしていたこのプロパティは、設定された方法により、クエリがUserテーブルへの内部結合になりました。私の謝罪と答えに感謝します。 –

答えて

1

を私はあなたの問題がInclude呼び出しによるものではないと思います。 documentationとよれば、そのようなメソッドが存在する場合

この拡張方法は、 IQueryableソースオブジェクトのInclude(String)メソッドを呼び出します。 ソースが IQueryableの場合、一致する方法がない場合は、 はありませんです。言い換えれば

はに変換されようとしている:

var item = db.Items.Include("User").Include("PrimaryNode").FirstOrDefault(i => i.ItemId == id); 

私の質問で、あなたがあなたのDBに適切Usersに既存の行と関連し、そのIDを持つItemPrimaryNodesテーブルを持っていることを確認しています?最後にIncludeメソッドを呼び出すと、結合に変換されるので、関係のFKがその参照のPKと一致しない場合、クエリは期待しているものを返してはなりません。

あなたがExplicit Loadingを使用することができます関連のプロパティをロードするために別のバリアントを試してみたい場合はとにかく、:

var item = db.Items.FirstOrDefault(i => i.ItemId == id); 
context.Entry(item).Reference(p => p.PrimaryNode).Load(); 
context.Entry(item).Reference(p => p.User).Load(); 
+0

また、Lambdasを使用することもできます。 'db.Items.Include(item => Item.User)'です。私はリファクタリングをもっと親切にしているので、これを持ってきます。 – Cameron

+0

Explicit Loadingの例でデータベースが3回コールされると思いますか?チェーン付きインクルードを使用すると、ジョインでデータベースを1回呼び出すことができます。 –

1

私は自分の状況を遅延読み込みすることをお勧めします。その後、

public class Item 
{ 
    [Key] 
    public int ItemId { get; set; } 
    public string ItemName { get; set; } 
    public virtual Node PrimaryNode { get; set; } 
    public virtual User User { get; set; } 
} 

そして::ちょうどUserと仮想PrimaryNodeを作る

var db = new MyContext(); 
var item = db.Items.FirstOrDefault(i => i.ItemId == id); 
+0

提案していただきありがとうございます。これは私のシナリオでは正しく動作しません.Lazyの読み込みが正しく理解されていれば、私は接続されていないシナリオで作業しています。私は、データベースからデータを取得し、表示のためにWebページに戻しています。 –

+0

@AndyE ...あなたはようこそ。レイジーローディングは、エンティティまたはエンティティを参照するプロパティに初めてアクセスしたときに、エンティティまたはエンティティのコレクションがデータベースから自動的にロードされるプロセスです。 –

0

他の人が述べたように、私はあなたの問題が含まによるものではないと思います。しかし、私は次の方法は価値があると思います。機能的には、チェーン付きインクルードで何をしているのと同等ですが、コードの意図をユーザーに明確にするなど、いくつかの利点があります。

ザ・エクステンション方法で配置することができます含まれています

using System.Data.Entity; 
using System.Linq; 

namespace Stackoverflow 
{ 
    public static class EntityExtensions 
    { 
     public static IQueryable<Item> IncludePrimaryNode(this IQueryable<Item> query) 
     { 
      // eager loading if this extension method is used 
      return query.Include(item => item.PrimaryNode); 
     } 

     public static IQueryable<Item> IncludeUser(this IQueryable<Item> query) 
     { 
      // eager loading if this extension method is used 
      return query.Include(item => item.User); 
     } 
    } 
} 

すると、次のように拡張機能を使用することができます

using (var db = new MyContext()) 
{ 
    var itemQuery = db.Items.IncludeUser(); 

    itemQuery = itemQuery.IncludePrimaryNode(); 

    var item = itemQuery.FirstOrDefault(i => i.Id == 1); 
} 

それは同じことをするだけで、別の方法ですが、私は好きそれがコードに追加された明確さ。