2017-04-18 12 views
3

エンティティフレームワークでいくつかのオブジェクトを手動で初期化するコレクションを正しく処理できないという問題があります。エンティティフレームワークでのLazyコレクションの読み込みが遅い

パブリックコレクションプロパティを返すためにプライベートフィールドを使用するという多数の例に基づいてコードを使用しています。例えばこのようにquestion

LINQクエリでこのフィールドを使用する場合は、問題に遭遇しています。

私のモデル構造は以下の通りです。

public abstract class Parent 
{ 
    [Key] 
    public int Id { get; set; } 

    public virtual List<Child> Childeren 

    ... 
} 

public abstract class Child 
{ 
    [Key] 
    public int Id { get; set; } 

    protected List<Grandchild> _grandchilderen; 

    public virtual List<Grandchild> Grandchilderen 
    { 
     get 
     { 
      if (_grandchilderen== null) 
       SpawnGrandchilderen(); 
      return _grandchilderen; 
     } 
     set { _grandchilderen= value; } 
    } 

    private void SpawnGrandchilderen(){ 
     _grandchilderen=new List<Grandchild>(){new Grandchild(), new Grandchild()}; 
    } 

    ... 
} 

public abstract class Child 
{ 
    [Key] 
    public int Id { get; set; } 

    ... 
} 

私は

parent_instance.Childeren.SelectMany(C=>C.Grandchilderen).ToList() 

SpawnGrandchilderen(のようなクエリを使用した場合)は、データベースからロードされているはずのデータが上書きされ、すべての子どもに呼ばれています。

ゲッターの先頭にブレークポイントを配置すると、_grandchilderenが常にnullであることがわかります。

linqクエリの前にブレークポイントを置き、実行を続行する前にウォッチウィンドウを使用して手動で子ノードを探索すると、コードが正常に動作するようになりました。

これはレイジーローディングの問題であると思いますが、この問題を効率的に解決する方法についてはわかりません。


編集: 私はもう少しチャンスをうかがっを行っていると私が見つけたすべてがある:それは最初Grandchilderenリストにアクセスすると

は常にNULLです。

SpawnGrandchilderen()_grandchilderen = new List<Grandchild>()に置き換えて、ブレークポイントを行に付けると、行がヒットしているのがわかりますが、空の配列が返されると予想されるときにデータベースからのデータが実際に返されます。

しかし、私は

_grandchilderen = new List<Grandchild>(){new Grandchild()}; 

と行を置き換える場合は、ゲッターから返された値は、私のデータベースのデータのどれが含まれていませんが、私の新しく作成された孫を含んありません。

ここでは奇妙なEFブードーが起こっているので、トラブルシューティングの方法がわかりません。

+0

に自分のクラスを変更することによって:parent_instance.Childeren.Select(X => x.Grandchilderen).SelectMany(C => C).ToList(); – jdweng

+0

'List'の代わりに' ICollection'を使ってみましたか? –

+0

インデックスでアクセスできるように私のコレクションにアクセスする必要があるので、リストと一緒に行く必要がありました – Hugoagogo

答えて

0

私はgrek40のヒントに基づいて自分自身を解決することができました。関数の最初の呼び出しが値を変更することなく終了するようにして、動作させることができました。 (非EFコードから)適切にリンクされるようにします。

以下試し次関数

private bool _grandchilderenloaded = false; 
protected List<Grandchild> _grandchilderen; 

public virtual List<Grandchild> Grandchilderen 
{ 
    get 
    { 
     if (!_grandchilderenreloaded) 
      { 
      _grandchilderenreloaded = true; 
      if (Grandchilderen == null) // Note this getter calling itself here is where the magic happens 
       SpawnGrandchilderen(); // The Db value has now been loaded, if it was non null do some setup. 
      } 
     return _grandchilderen; 
    } 
    set { _grandchilderen= value; } 
} 
関連する問題