我不知道这是好事还是坏事以及如何适应这一点。
亲子关系非常简单明了。没什么大不了的。您可以看到以下代码:
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
属性为null
,childCollection
属性为Parent
。但这不会发生。在第二行代码执行后,parent.Childs
填充了子对象,并且子对象中的每个Parent
属性都等于parent
,我不想要它(我应该要它吗? )。
为什么entityframework的行为如此?我应该注意哪些情况?如果我在不知道此行为的情况下更改childCollection
会发生什么?
答案 0 :(得分:1)
与许多现代ORM一样,Entity Framework不仅设计用于将查询结果映射到实体(对象),还将其关系映射到属性。如果您声明导航属性(例如您在类中使用了Childs
或Parent
属性),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
中找到更多详细信息