为什么子实体在实体框架中自动绑定到父实体

时间:2016-04-07 13:17:07

标签: c# entity-framework entity-framework-6

我不知道这是好事还是坏事以及如何适应这一点。

亲子关系非常简单明了。没什么大不了的。您可以看到以下代码:

父对象:

public class Parent
{
    public int Id {get;set;}
    public List<Child> Childs {get;set;}
}

子对象

public class Child
{
    public int Id {get;set;}
    public int ParentId {get;set;}
    public Parent Parent {get;set;}
}

代码周围的某处(比如控制器的索引方法)

var parent = parentRepository.FindAll(x=> x.Id == 10).ToList();
var childCollection = childRepository.FindAll(x=> x.ParentId == parent.Id).ToList();

当我运行上面的代码时,我希望parent对象的Childs属性为nullchildCollection属性为Parent。但这不会发生。在第二行代码执行后,parent.Childs填充了子对象,并且子对象中的每个Parent属性都等于parent,我不想要它(我应该要它吗? )。

为什么entityframework的行为如此?我应该注意哪些情况?如果我在不知道此行为的情况下更改childCollection会发生什么?

2 个答案:

答案 0 :(得分:1)

与许多现代ORM一样,Entity Framework不仅设计用于将查询结果映射到实体(对象),还将其关系映射到属性。如果您声明导航属性(例如您在类中使用了ChildsParent属性),EF将(懒惰地)将这些属性自动映射到其引用的实体(您可以找到有关导航属性here)的更多信息。

此行为是设计使然,其目的是避免使用连接显式执行查询,并且无需调用childRepository.FindAll(x=> ...,因为只要您访问所有相关的Child实体,就会被EF加载Childs对象中的Parent属性。

另请注意,EF实施了更改跟踪系统,因此,如果您修改从数据库中提取的实体,EF会在您第一次在上下文中调用SaveChanges时跟踪这些更改并将其保留。

作为旁注,EF体系结构实际上是一起使用的UnitOfWork和Repository模式的示例(DbContext是UoW,每个DbSet的工作方式都像存储库),所以我强烈建议您阅读有关EF的更多信息以避免滥用它使用另一个抽象(例如您的存储库)自己构建或重新实现它们。

答案 1 :(得分:1)

是的,这是EF的正常行为。在childCollection实现调用ToList的那一刻,当您再次检查parent实例时,将运行关系修正并检查其FK是否具有相同值的Child实体您当前parent的PK已在对象上下文中加载。如果是这种情况,将立即使用Parent.Childs个实体设置Child属性。这与延迟加载无关,实际上您的模型不能满足延迟加载所需的所有requirements,例如导航属性应为virtual

无法禁用此行为,但如果您在构建查询时使用AsNoTracking扩展方法,则返回的实体将不会缓存在DbContext中:

var query= context.Childs.AsNoTracking().Where(c=>c.ParentId==10);

您还可以在此优秀的post

中找到更多详细信息