2013-10-15 9 views
10

私はN×N個のテーブルを持っている、と想像どこ:LINQを含める+メソッド

ユーザー(ID、...)< - UserAddresses(IDは、ユーザーID、あるAddressId、有効、...) - >アドレス(IDを、...)

UserAddressesには、FKのユーザーとアドレスが含まれています。 私が知る限り、Entity Framework Userによって作成されたEntityには、UserAddressesへのコレクションが含まれています。アドレスにはUserAddressesへのコレクションが含まれており、特定のUserAddressにはUserと1つのAddressに対する1つのrefenreceが含まれています。

ここでlinqで次のクエリを作成します。 特定のユーザーIDの場合、enabledフラグがtrueに設定されたuserAddressesのみを取得します。 特定のユーザーIDの場合、userAddressesには複数のエントリを含めることができますが、この特定のユーザーに対して1つのみが設定されます。

私が行うことができますクエリは次のとおりです。

context.User.Include(x => x.UserAddresses) 
      .Include(x => x.UserAddresses.Select(y => y.Address)) 
      .Single(x => x.id == USER_ID) 

しかし、私が本当に欲しいのは、そのユーザーのすべてのUserAddressesをロードすることはない... TRUEにsetted有効に含まれている唯一の、!

誰かがこのクエリを実行するのを手助けできますか?

+0

どのような 'Include'を使用していますか?私が知る限り、 'System.Data.Objects.ObjectQuery'の' Include'メソッドはstringの引数を1つだけ受け取りますか? –

+0

@ KingKingラムダ式を文字列にフォーマットし、それを "ネイティブ" ObjectQueryインクルードメソッドに渡す拡張メソッドを実行しました。 – anotherNeo

+0

もしそうなら、あなたの問題への答えは「不可能」、「インクルード」はそれほど強力ではないので、インクルードする前に「フィルタ」を実行することはできません。 –

答えて

14

EFには、関連プロパティを部分的にロードする方法はありません。あなたが必要なものだけ取るために匿名型に選択してみてください:

var result = context.User 
    .Where(u => u.Id == userId) 
    .Select(u => new { 
     Addresses = u.UserAddresses.Select(ua => ua.Address) 
      .Where(a => a.Enabled), 
     User = u // if you need this as well 
    }) 
    .Single(); 

これはresult.User.UserAddressesをロードしませんが、result.Addressesは正確に何をしたいがあります。

すべてをUserクラスの一部として返す場合は、result.Userを切り離し、result.User.UserAddressesを更新してresult.Addressesを指すようにする必要があります。

別の代替選択肢は、load()を使用しての代わりに、(インクルードされ
+0

私はUserエンティティを関連するすべてのもので返す必要がありますが、コレクションのすべてがマッピングされているわけではありません。したがって、匿名の型は正しくないと思う:/ – anotherNeo

+0

@goncaloRD:残念ながら 'where'条件は' Include'を使っては使用できません。これがあなたの最善の選択肢です。 – Ocelot20

+0

@ChaseMedallionありがとう、これは私が必要とするものです。クエリは完全に行われ、EFオブジェクトは必要な方法でマップされます。 Typeを作成して、オブジェクトをタイプ化し、ビジネスレイヤーで使用するようにしました。 – anotherNeo

1

):

var foundUser = context.User.Single(x => x.Id == USER_ID); 

context.Entry(foundUser).Collection(u => 
u.UserAddresses).Query().Where(userAddress => 
userAddress.Enabled).Load(); 

ロード()メソッドは、いくつかのシナリオではEFによって無視することができることを覚えておいてください:

  1. 場合Lazy Loading機能と一緒にEFを使用している場合、オブジェクトをフェッチすると、クラスにVirtualとしてマークされている関連するすべてのコレクションが表示されます。したがって、これを行うことによって:

    context.User.Single(x => x.id == USER_ID);

    UserクラスのプロパティからVirtualキーワードを削除して、コレクションのレイジーロードをオフにしない限り、Userに関連付けられたすべてのUserAddressを取得します。

  2. プログラムでUserAddressesコレクションを追加/削除している場合は、context.SaveChanges()を呼び出します。あなたのコンテキストを捨てることなく、次にUserオブジェクトをロードすると、UserAddressesコレクションはDBからではなくEFコンテキストキャッシュからロードされます(あなたの最新の変更)。この場合、コンテキストを破棄して、コンテキストからユーザを取得する前に新しいコンテキストをインスタンス化する必要があります。たとえば、UserAddressesコレクションに5つのアイテムを持つUserを持っていて、アイテムの1つを無効にして(item.Enabled = false)、コンテキストを破棄せずにcontext.SaveChanges()を呼び出すと、次回Userオブジェクトを取得します同じコンテキストからは、コレクションにはコンテキストキャッシュから5つのアイテムが既にあり、Load()メソッドは無視されます。

PS:以下のすべての条件が適用された場合

遅延読み込み機能がONである:

  1. context.Configuration.LazyLoadingEnabled = TRUE。
  2. context.Configuration.ProxyCreationEnabled = true;
  3. UserAddressesは、UserクラスのVirtualに定義されています。
関連する問題