imm*_*rza 3 c# entity-framework
我已禁用延迟加载,但当访问引用实体/实体的属性时,实体会自动从数据库加载。为什么?应该不能再访问了吧?
My EF version="6.1.3"
Run Code Online (Sandbox Code Playgroud)
以下行加载部门数据,而我期望它不应该加载,因为我已禁用延迟加载并且导航属性是非虚拟的。
Student student = context.Student.select(x => x.Department).First();
Run Code Online (Sandbox Code Playgroud)
课程:
public class Student
{
public string Name { get; set;}
public string Age { get; set;}
public string Date { get; set;}
public Department department { get; set }
}
public class Department
{
public string Id { get; set; }
public class Name { get; set; }
public Student Student { get; set }
}
Run Code Online (Sandbox Code Playgroud)
语境
public StudentContext : DbContext
{
public StudentContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
Run Code Online (Sandbox Code Playgroud)
什么是延迟加载?
在执行一些初始 SQL 查询并加载一些实体后,它可以通过执行单独的数据库查询来加载相关数据。
首先让我们回顾一下你的课程:
考虑到这些,您将获得以下课程:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Age { get; set; }
public string Date { get; set; }
public virtual Department Department { get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在让我们看看启用延迟加载时会发生什么。例如,您正在加载学生:
Student bob = context.Students.FirstOrDefault(s => s.Name == "Bob");
Run Code Online (Sandbox Code Playgroud)
这将生成类似于
SELECT TOP(1) Name, Age, Date, Department_Id
FROM Students
WHERE Name = 'Bob' --actually name will be passed as query parameter
Run Code Online (Sandbox Code Playgroud)
更重要的是,该 SQL 查询将被执行,来自服务器的响应将被加载到内存中并映射到Student实体。除了已加载其 ID 外,没有与部门相关的任何内容。现在,如果您尝试获取部门详细信息
var departmentName = bob.Department?.Name;
Run Code Online (Sandbox Code Playgroud)
EF 将生成 SQL 查询以加载相关部门的详细信息。就像是
SELECT d.Id, d.Name
FROM Students s
INNER JOIN Departments d ON s.Department_Id = d.Id
WHERE s.Id = 42 -- assume Bob has this id
Run Code Online (Sandbox Code Playgroud)
这个查询将被执行。这是服务器的第二次往返。这就是延迟加载的工作原理。
当延迟加载被禁用时,将不会对服务器进行第二次查询。您将只有第一次查询时加载的数据。即部门实体将是null,您将无法获得它的名称。
现在您的情况 - 您正在通过第一次查询加载部门数据。实际上你的代码不会编译,因为你应该使用Department实体:
Department dep = context.Student.Select(x => x.Department).First();
Run Code Online (Sandbox Code Playgroud)
启用或禁用延迟加载不会影响它。因为正如我刚刚写的,延迟加载会影响加载相关数据的进一步查询。但首先不是加载初始数据的查询。在你的情况下,它看起来像
SELECT TOP(1) d.Id, d.Name
FROM Students s
LEFT OUTER JOIN Departments d ON s.Department_Id = d.Id
Run Code Online (Sandbox Code Playgroud)