4

抽象エンティティ/クラスで構築された EF4 モデルがあります。

代替テキスト

StateエンティティにCountryというナビゲーション プロパティがあることに注目してください。

注: 遅延読み込みが無効になっているため、オンデマンドで熱心に読み込む必要があります。

さて、次の方法がある場合:

public Location FindSingle(int id)
{
   return _repository.Find().WithId(id).SingleOrDefault();
}

デフォルトでは、関連付けは返されません。しかし、明示的にしたいときに、どうすればアソシエーションを動的にeager-loadできますか?

これはできない:

return _repository.Find().WithId(id).Include("Country").SingleOrDefault();

「Country」というナビゲーション プロパティを持たないLocationという抽象クラスを使用しているためです。で実際にクエリを実行するまで、派生型が何であるかはわかりません.SingleOrDefault

だから、ここに私がしなければならなかったことがあります:

public Location FindSingle(int id, bool includeAssociations = false)
{
    var location = _repository.Find().WithId(id).SingleOrDefault();
    return includeAssociations
                       ? LoadAssociation(location)
                       : location;
}

private Location LoadAssociation(Location location)
{
   // test derived-type, e.g:
   var state = location as State;

   if (state != null) 
      return _repository.Find().OfType<State>().Include("Country").WithId(id).SingleOrDefault();
}

基本的に、私は2つの同一の呼び出しを行っています。それは機能しますか?はい。それはきれいですか?いいえ、実際には「熱心な読み込み」ではありません。

これが正しい解決策ではないことはわかっています。適切な解決策を考えてもらえますか? (はい、ストアド プロシージャを使用できることはわかっていますが、ここでリポジトリ/モデルを実際に調べたいので、エンティティがグラフに正しくアタッチされ、編集の準備ができています)。

Left Outer Joinが.Include発生しますが、問題は「場所」エンティティ セットで作業していることです。「州」を必要と.Includeしますが、「州」は「場所」エンティティ セットに属します (派生クラスは親のエンティティ セットに属します)。

したがって、私の質問は実際にはかなり一般的なものだと思います-子が何であるかが事前にわからない場合、抽象エンティティの子に.Includeを行うにはどうすればよいですか?

.OfType<T>()T が何であるかがわからない (呼び出しコードもわからない) ため、最初に (そして派生型の .Include を)使用できないことを覚えておいてください。したがって、ここではジェネリックを使用できません。

4

1 に答える 1

3

ここでの本当の問題は、 を保持しているIdが、それが何を表しているかわからないということCountryですState。ある時点で、それが何であるかを知っていたと思われますが、その情報を保持していませんでした。

リポジトリからをロードした後Location、関連する関係プロパティにアクセスするためにキャストするタイプをどのように知るのでしょうか? おそらく、asまたはiswith キャストを使用する必要があり、これらのプロパティにアクセスできます。これがまた臭い。

ここでの最良のオプションは、 Location オブジェクトのTypeと の両方を維持Idして、適切なリポジトリ メソッドを使用して再ロードできるようにすることです。

もう 1 つのオプションは、すべてのオブジェクトがLocation およびLocations コレクションを持つLocationように、リレーションシップをクラスに移動することです。これで、それらをと に含めることができます。親がない場合は null を使用し、子がない場合は空のコレクションを使用します。大陸または都市を Location クラスに追加すると、同じモデルを使用するのに最適な状態になります。Location.Parent.ChildrenIncludeState.ParentCountry.Children

このような状況で時々使用できる最後のオプションは、2 つのクエリを共通の基本型に変換した後にユニオンすることです。たとえば、次のようなものです。

context.Locations.OfType<Country>().Include("States").Cast<Location>().Union(context.Locations.OfType<State>().Include("Countries).Cast<Location>());
于 2010-10-25T03:40:51.130 に答える