读取关联数据(EF Core2.1.1)

对象-关系映射框架比如EF有三种 方式使用 模型中的导航属性来加载关联数据。

一、.Lazy Loading.(关联数据在访问导航属性时被透明的加载,不需要特别的代码,自动的加载)

当一个实体第一次读取的时候,关联数据不会被检索。然后,当你第一次访问这个实体的导航属性的时候,导航属性需要的数据自动的被检索。每当你第一次从导航属性获取数据时,都会向数据库发送查询。这样,会导致多个查询被发送到数据库。一个是实体本身,另外,每当实体的关联数据第一次被访问的时候。EF6.x的DbContext类默认启用了Lazy loading.

lazy loading 不支持AsNoTracking()方法,使用了.AsNoTracking(),lazy loading会发生异常。

而EF Core1的版本是不支持Lzay Loading的。从EF2.1.开始支持Lazy Loading,但必须是可以覆写的导航属性,也就是 说定义为虚 virtual属性,和能够被继承的。需要进行以下设置。

1、安装代理类

PMC:Install-Package Microsoft.EntityFrameworkCore.Proxies -Version 2.1.1

在Startup.cs配置文件中,ConfigureService方法中,

//启动文件,在依赖注入容器中注册数据库上下文对象。
2、services.AddDbContext<SchoolContext>(options =>
options.UseLazyLoadingProxies().UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); //如果未在Context中添加UseLazyLoadingProxies,导航属性不会添加。

departments =context.Departments;

foreach(Department d in departments)

{

 foreach(Course c in d.Courses)

{

   courseLIst.Add(d.Name + c.title)

}

}

二、EagerLoading  (关联数据在初始的查询里面就从数据库加载)

当实体第一次被读取的时候,关联的数据一起被检索。这将会导致仅有的连接查询会检索所有需要的全部数据。通过EF core使用Include方法和ThenInclude方法来指定eagerLoding.

departments =context.Departments.Include(x =>x.Course) //一条语句就从数据库中加载所有的关联属性。

foreach(Department d in departments)

{

 foreach(Course c in d.Courses)

{

  courseList.Add(d.Name +c.Title);

}

}

三、Explicit loading (关联数据后来才能被显式的从数据库加载)

1.这个与lazy loading相似,除了需要显式的使用代码来检索关联数据。当你访问一个导航属性的时候,不会自动发生。需要通过对象状态管理器(object state manager)Entry手动的加载关联数据,,调用Collection.Load(导航属性为集合)方法和reference.Load(导航属性为单个实体)方法。你使用显式加载仅仅是关闭了lazy loading。

departments =context.Departments.Tolist();

foreach(Department d in departments)

{

 context.Entry(d).Collection(d =>d.Courses).Load(); //用Entry load()代码明确从数据库加载关联数据。

 foreach(Course c in d.Courses)

{

  courseList.Add(d.Name +c.Title);

}

}

2.你能够使用单独的查询来检索数据,EF会 修复导航属性。也就是说EF自动地将它们所属的单独检索的实体添加到先前检索实体集的导航属性中。对于检索相关数据的查询,可使用Load方法而不是返回列表或对象的方法,例如:ToList()或者 Single()

departments =context.Departments.Include(x =>x.Courses)

foreach(Department d in departments)

{

  context.Courses.Where(c =>c.DepartmentID == d.DepartmentId).Load(); //从数据库中加载实体的导航属性,使用load();

foreach(Course c in d.Courses) // 由于EF  Core修复了导航属性,因此,这里不是lazy loading,而是eager loading.

{

courseList.Add(d.Name +c.Title)

}

}

因为lazy loading和explicit loading不会立即查询属性值,因为它们都属于延迟加载(deferred loading).

性能考虑

如果每一个实体的导航属性都需要被查询,eager  loading通常能提供最好的性能,因为只有一个查询被发送到数据库,比起检索单个实体的独立的查询,减少了对数据库访问来回的次数,显得更加高效。

另一方面,在一些情况下,Lazy loading更加高效。Eager loading可能导致非常复杂的连接查询,SQL服务器不能有效的处理。如果你仅仅需要访问一个实体集的其中一部分(子集)实体的导航属性,则延迟加载可能会执行得更好,因为预先加载将检索比您需要的更多数据。 如果性能至关重要,最好以两种方式测试性能,以便做出最佳选择。

延迟加载可以掩盖导致性能问题的代码。例如,处理大量的实体,并且在每次迭代中使用了多个导航属性,没有指定eager loading或explicit loading ,这样的代码执行效率非常低。因为多次往返数据库。一个应用程序在本地开发过程中运行良好,但当移植到Azure SQL数据库时,由于延迟增加和Lazying loading可能出现性能问题。

序列化 的时候使用lazy loading将导致失控的链式反应,序列化之前要关闭lazy loading.

原文地址:https://www.cnblogs.com/liuyuanhao/p/9452658.html