EF6虚拟导航属性是否导致SQL查询?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EF6虚拟导航属性是否导致SQL查询?相关的知识,希望对你有一定的参考价值。
假设我有一个具有虚拟导航属性的实体,如下所示:
public class School
{
public long Id { get; set; }
public virtual ICollection<Students> Students { get; set; }
}
据我了解,EF6使用代理来启用Students
的延迟加载,但执行以下LINQ查询:
var myStudent = this.Students.Single(x => x.Id == id);
var studentsCount = this.Students.Count();
var bestStudents = this.Students
.OrderByDescending(x => x.GPA)
.Take(5)
.ToArray();
结果进入SQL查询(就像IQueryable<T>
那样)?或者它只是一个延迟加载的集合,并将在第一次请求后将所有学生加载到内存中,然后执行简单的IEnumerable<T>
LINQ行为?
在Entity Framework中查询实体时,返回的对象(始终)不是您认为它们的对象类型。在幕后,它创造了一个继承自你的班级的全新类。因为OOP允许子类存储在作为超类输入的变量中,所以你永远不会注意到。这是你提到的“代理”。这就是virtual
函数允许延迟加载的原因。子类重写您的虚方法,并包含在返回之前延迟加载额外数据的代码。
然后,重写的属性调用将检查上下文以查看是否已加载导航属性。如果是,它只是返回它们。如果不是,它将进行额外的SQL调用以加载它们,并将它们存储在DbContext
中以供日后使用。
在您更新的问题中,我的理解是运行这些代码行将导致执行3个单独的查询。
公共虚拟属性是EF6中的延迟加载。您可以为DbContext禁用延迟加载,或者在IQueryable上使用.Include()方法在第一个查询中包含该属性。
http://www.entityframeworktutorial.net/EntityFramework4.3/lazy-loading-with-dbcontext.aspx
https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx
一旦你“遍历”列表(例如通过调用.Single(),. Count()或.ToArray()方法),就会执行查询,并且您有一个内存中的学生列表。有关查询执行的更多详细信息,请参阅https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/query-execution。
第一个示例将导致3个查询,其中第一个返回具有给定Id的学生,第二个返回学生计数,第三个返回由GPA属性订购desc的前5个学生。
关于DDD =>您可以使用一些分层架构,使用ApplicationServices和DomainServices,其中DomainServices执行域逻辑,ApplicationServices加载/转换数据。
例如,https://aspnetboilerplate.com/模板是域驱动设计的良好起点。
假设第二个代码块在“学校”实例的范围内执行(所以'this'是'School'的实例 - 在我的示例中,在school19下面),那么下面的场景是可能的:
A)您已经加载了这样的'School'实例(启用了延迟加载):
var school19 = dbContext.Set<School>()
.FirstOrDefault(school => school.Id == 19)
然后,用于访问“学生”属性的3行代码将触发一次额外的数据库命中
var myStudent = this.Students.Single(x => x.Id == id);
执行,但随后的两个语句不会再发生数据库命中。
B)如果您已经加载了像这样的“学校”实例(启用了延迟加载):
var school19 = dbContext.Set<School>()
.Include(school => school.Students)
.FirstOrDefault(school => school.Id == 19)
然后,用于访问“学生”属性的3行代码不会触发额外的数据库命中。
C)如果禁用延迟加载,则
- A)会导致空引用异常
- B)表现相同
作为最后一句话,如果'this'是对DBContext类的实例的引用,该实例具有属性
public Set<School> Schools { get; set; }
然后它会触发3个不同的数据库调用。但结果是不同的,因为这将在所有学校的背景下执行,而我的上述假设仅适用于单个学校。
以上是关于EF6虚拟导航属性是否导致SQL查询?的主要内容,如果未能解决你的问题,请参考以下文章