2017-03-27 72 views
2

我已禁用延迟加载,但实体是从数据库中自动加载访问属性指实体/实体时。为什么?它不应该再被访问?禁用延迟加载仍会加载相关的实体。为什么?

My EF version="6.1.3" 

以下线路负荷部门的数据,而我期待它不应该,因为我已经停用延迟加载,并导航属性非虚。

Student student = context.Student.select(x => x.Department).First(); 

类:

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 } 
} 

语境

public StudentContext : DbContext 
{ 
    public StudentContext() 
    { 
     this.Configuration.LazyLoadingEnabled = false; 

    } 

} 
+5

您的查询明确要求部门。当然,它会加载部门数据。 – Amy

+0

所以你想[懒加载](https://msdn.microsoft.com/en-us/library/jj574232(v = vs.113).aspx)?你已经配置了所有配置以便加载(不虚拟,访问孩子,关闭它)。 –

+0

谢谢,所以我对延迟加载的理解是错误的。你的意思是,尽管延迟加载被禁用,但如果我们使用x.blah访问导航属性,EF会显式加载它,并不会抱怨“懒惰加载已禁用,因此我无法加载它。”更好地尝试“加载加载”或“显式加载” ,“ – immirza

回答

1

你有什么 “懒加载” 方式错误的想法。

context.Student.Select(x => x.Department).First(); 

您明确要求Department。英孚将会兑现这一要求。关于您的查询没有任何“懒惰”:您是明确要求Department

是的,您通过导航属性请求Department,但这并不重要,因为您没有使用Student的实例。 您直接向数据库发出查询。

您现在有一个Department。懒惰加载现在开始发挥作用,因为您完成了显式查询。

该部门有一个小孩财产,Student。由于延迟加载处于禁用状态,即使数据库中存在数据,该属性也将为空。如果您引用该属性,则它将为空,因为延迟加载被禁用 - EF不会为您自动获取数据。您必须明确查询该属性。

好的,所以说你明确要求一个Student对象。它的Department属性将为空,因为延迟加载被禁用。引用该属性不会导致它被加载。您将不得不显式查询该属性。

+0

谢谢,我明白了。 – immirza

1

什么是延迟加载?

它是由后做单独的数据库查询加载相关数据的能力,你有 执行一些初步的SQL查询,并加载一些实体。

,首先让我们来回顾你的类:

  • 教研室不是1:1间与学生的关系。每个部门都可以包含很多学生
  • 学生没有一个ID属性
  • 部门也许应该有整数ID
  • 为了支持延迟加载导航性能应虚拟

考虑到这些,您将获得以下课程:

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; } 
} 

现在让我们来看看会发生什么启用延迟加载。例如。您正在加载学生:

Student bob = context.Students.FirstOrDefault(s => s.Name == "Bob"); 

,将产生类似

SELECT TOP(1) Name, Age, Date, Department_Id 
FROM Students 
WHERE Name = 'Bob' --actually name will be passed as query parameter 

而且更重要的是,该SQL查询将被执行,并从服务器响应将被加载到内存中,并映射到Student查询实体。除了ID已加载外,没有任何与部门相关的信息现在,如果您尝试获取部门详情

var departmentName = bob.Department?.Name; 

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 

并且此查询将被执行。这是服务器的第二次往返。这就是懒加载的工作原理。

延迟加载被禁用将不会有第二个查询到服务器。您将只有第一次查询加载的数据。即部门实体将是null,你将无法获得它的名字。


现在你的情况 - 你正在通过第一次查询加载部门数据。其实你的代码不能编译,因为你应该使用Department实体:

Department dep = context.Student.Select(x => x.Department).First(); 

启用或禁用延迟加载不会影响。因为正如我刚刚写的,延迟加载会影响进一步查询加载相关数据。但不是首先加载初始数据的查询。在你的情况下,它看起来像

SELECT TOP(1) d.Id, d.Name 
FROM Students s 
LEFT OUTER JOIN Departments d ON s.Department_Id = d.Id 
+1

谢谢,优秀的解释。 – immirza

+1

@immirza欢迎您。请记住 - 懒加载为您提供了轻松访问相关实体的好处,就像它们已经从服务器加载一样,但是您应该小心,因为每次您要进行新的数据库往返时 –

相关问题