2017-08-02 17 views
2

私は他の子のコレクションを持っているそのうちの一つ2機種、持っている:Entity Frameworkの遅延ロードされたコレクションが時々ヌル

var parent = _dbContext.Parents.FirstOrDefault(p => p.Id == parentId); 

:このコードは、ウィジェットの> 99%のために働く

[Table("ParentTable")] 
public class Parent 
{ 
    [Key, Column("Parent")] 
    public string Id { get; set; } 

    [Column("ParentName")] 
    public string Name { get; set; } 

    public virtual ICollection<Widget> Widgets { get; set; } 
} 

[Table("WidgetTable")] 
public class Widget 
{ 
    public string Year { get; set; } 

    [Column("Parent")] 
    public string ParentId { get; set; } 

    public string Comments { get; set; } 

    [Key, Column("ID_Widget")] 
    public int Id { get; set; } 

    [ForeignKey("ParentId"), JsonIgnore] 
    public virtual Parent Parent { get; set; } 
} 

を通常、parent.Widgetsは複数のアイテムを含むコレクションです。ただし、いくつかの例では、parent.Widgetsはnullです(アイテムのないコレクションではありません)。

私は、クエリアナライザーを使用して、親のクエリーと、その親に属するウィジェットのクエリーの両方をトレースしました。どちらも、私が期待する行を正確に返します。ただし、1つまたは2つの親IDのモデルでは、Widgetsコレクションの値はnullになります。一部のインスタンスでは遅延ロードされたコレクションがnullになる可能性がありますが、他のインスタンスではnullになる可能性はありますか?

+0

'parent.Widgets'はnullで、' parent'ではないと確信していますか? – mjwills

+0

@mjwills:はい、クイックウォッチを使って確認しました。 – Andy

+0

私は理解できません...ウィジェットを持たない一部の親は空のコレクションを返しますが、ウィジェットを持たない他の親もnullを返すと言っていますか?または、ウィジェットを持たないすべての親がnullを返すのでしょうか? –

答えて

3

この状況は、dbContextの有効期間がAdd、saveChanges、およびretrieveの間に開いたままになっているとよく発生します。例えば

var context = new MyDbContext(); // holding Parents. 
var testParent = new Parent{Id = "Parent1", Name = "Parent 1"}; 
context.Parents.Add(testParent); 

この時点で、あなたがした場合:

var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1"); 

あなたは親を取得しないでしょう。選択は

context.SaveChanges(); 
var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1"); 

これはあなたのコンテキストがこの実体を知っていて、あなたが作成したオブジェクトへの参照を持っているので、あなたが挿入されていた親への参照を返します... ..コミット状態から来ているので。データ状態にはなりません。ウィジェットの定義はget/set auto-propertyで定義されただけなので、この場合のウィジェットコレクションは#nullになります。

あなたがこれを行う場合:この場合

context.Dispose(); 
context = new MyDbContext(); 
var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1"); 

それはデータ状態になるように、親が新しいコンテキストで知られていないが。 EFはあなたにウィジェットを読み込むためのプロキシリストを返すでしょう。#nullではなく、空のリストを返すことはありません。

EFでコレクションクラスを扱うときは、この動作を避けるために、コンストラクタ内で自動プロパティを使用しないようにするか、初期化しておくことをお勧めします。通常、Parentを作成した後でウィジェットを割り当てたいと思うでしょう。コレクションプロパティでセッターを使用することを奨励したくないので、デフォルトメンバーを初期化する方が良いです。例えば

private readonly List<Widget> _widgets = new List<Widget>(); 
public virtual ICollection<Widget> Widgets 
{ 
    get { return _widgets; } 
    protected set { throw new InvalidOperationException("Do not set the Widget collection. Use Clear() and Add()"); } 
} 

が、これは、実体参照のシナリオで台無しになるようコレクションプロパティに設定操作を実行することは避けてください。たとえば、あなたが年によって、あなたのウィジェットのコレクションを並べ替えしたいとしなかった場合は、のようなもの:

parent.Widgets = parent.Widgets.OrderBy(x=> x.Year).ToList(); 

は十分に無実のようだが、ウィジェットの参照はEFプロキシたとき、あなたはそれを吹き飛ばされました。 EFは今コレクションの変更追跡を実行できません。

コレクションを初期化すると、#nullコレクション参照で驚きを避ける必要があります。また、私はあなたのdbContextの寿命を見ます。要求または特定の操作の存続期間にわたって初期化されたものを保持しておくことは良いことですが、必要以上に長く生き続けることは避けてください。コンテキスト変更のトラッキングなどはリソースを消費し、操作を横断したときに、このような間欠的な奇妙な動作が見られることがあります。

関連する問題