【发布时间】:2019-02-25 10:57:06
【问题描述】:
参见以下简化示例:
学生班:
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public Grade Grade { get; set; }
}
年级:
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public ICollection<Student> Students { get; set; }
}
上下文类:
public class SchoolContext : DbContext
{
public SchoolContext() : base()
{
Configuration.LazyLoadingEnabled = true;
}
public DbSet<Student> Students { get; set; }
public DbSet<Grade> Grades { get; set; }
}
程序:
static void Main(string[] args)
{
using (var ctx = new SchoolContext())
{
Grade[] grades = ctx.Grades.ToArray();
Console.WriteLine(grades[0].Students == null); // True - As expected
var students = ctx.Students.ToArray();
Console.WriteLine(grades[0].Students == null); // False - ? Did not expect that
}
Console.Read();
}
会发生以下情况:
- 延迟加载已启用
-
Grades的列表已保存到数组中 - 正如预期的那样,等级对象的
Students导航属性是null - 单独查询得到
Students - EF 以某种方式填满了内存中数组的
Students导航属性。
如果不小心使用,这可能会给客户端带来非常昂贵的负载。 谁能解释为什么和导航属性是如何填充到数组中的?
【问题讨论】:
-
似乎没有启用延迟加载,因为它在
SchoolContext构造函数中设置为false。DbContext跟踪您使用同一个 DbContext 实例查询的所有实体,因此我猜它会因此在后台填充相关的导航属性。 -
作为测试,尝试更改代码以使用
ctx.Grades.AsNoTracking().ToArray();获取成绩,并查看加载学生后grades[0].Students == null是否仍然为假。 -
你可以做的另一个测试:在从数据库中获取学生之前尝试插入
ctx.Grades.Detach(grades[0]);,并检查grades[0].Students == null之后是否为假。 -
感谢@Alisson,我的真实示例设置了
Configuration.LazyLoadingEnabled = true;。在这里修改。 -
另外值得一提的是:如果启用了延迟加载(这似乎是您编辑后的情况),它应该在访问导航属性
Student后立即加载(因为这是目的延迟加载)。但是,当您第一次尝试时似乎没有发生这种情况,因为您的导航属性不是virtual。也许这正是你想要的。
标签: c# entity-framework lazy-loading