And*_*ndy 3 c# entity-framework ef-code-first entity-framework-6
我有2个模型,其中一个模型具有另一个模型的子集合:
[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; }
}
Run Code Online (Sandbox Code Playgroud)
此代码适用于99%以上的小部件:
var parent = _dbContext.Parents.FirstOrDefault(p => p.Id == parentId);
Run Code Online (Sandbox Code Playgroud)
通常,parent.Widgets是一个包含多个项目的集合。但是,在某些情况下parent.Widgets为null(不是没有项目的集合)。
我已经使用查询分析器来跟踪父查询和该父所属小部件的查询。两者都返回我期望的行;但是,一个或两个父ID的模型会导致Widgets集合的值为空。是什么导致延迟加载的集合在某些情况下为null,而在其他情况下则不是?
当dbContext生存期在Add,saveChanges,然后进行检索时处于打开状态时,通常会出现这种情况。
例如:
var context = new MyDbContext(); // holding Parents.
var testParent = new Parent{Id = "Parent1", Name = "Parent 1"};
context.Parents.Add(testParent);
Run Code Online (Sandbox Code Playgroud)
此时,如果要执行以下操作:
var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1");
Run Code Online (Sandbox Code Playgroud)
你不会有父母。选择来自提交状态。
context.SaveChanges();
var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1");
Run Code Online (Sandbox Code Playgroud)
这将返回对您已插入的父项的引用,因为上下文知道该实体,并具有对您创建的对象的引用。它不会进入数据状态。由于您的Widgets定义只是使用get / set自动属性定义的,因此在这种情况下Widgets集合将为#null。
如果您这样做:
context.Dispose();
context = new MyDbContext();
var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1");
Run Code Online (Sandbox Code Playgroud)
在这种情况下,新上下文无法识别父级,因此它将变为数据状态。EF将为您返回一个代理列表,用于延迟加载Widget,这些列表没有,因此您将获得一个空列表,而不是#null。
在EF中处理集合类时,最好避免使用自动属性,或者在构造函数中对其进行初始化,以避免这种行为。您通常需要在创建父级后分配窗口小部件。初始化默认成员会更好,因为您不希望鼓励在collection属性上使用setter。
例如:
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()"); }
}
Run Code Online (Sandbox Code Playgroud)
避免对集合属性执行Set操作,因为这会在实体参考方案中搞砸。例如,如果您想按年份对Widget集合进行排序并执行以下操作:
parent.Widgets = parent.Widgets.OrderBy(x=> x.Year).ToList();
Run Code Online (Sandbox Code Playgroud)
看起来足够纯真的,但是当Widgets参考是EF代理时,您就把它吹走了。EF现在无法对集合执行更改跟踪。
初始化您的集合,您应该避免使用#null集合引用感到惊讶。另外,我还要看一下dbContext的生存期。最好在请求或特定操作的生命周期内初始化一个,但要避免使它们存活超过必要的时间。上下文更改跟踪等会消耗资源,并且当它们进行操作时,您会发现这种看似间歇的奇怪行为。
| 归档时间: |
|
| 查看次数: |
946 次 |
| 最近记录: |