深入了解EntityFramework Core 2.1延迟加载(Lazy Loading)
前言
接下来会陆续详细讲解EF Core 2.1新特性,本节我们来讲讲EF Core 2.1新特性延迟加载,如果您用过EF 6.x就知道滥用延迟加载所带来的灾难,同时呢,对此深知的童鞋到了EF Core中也就造成了极大的心里阴影面积,那么到底该不该用呢?当然,完全取决于您。
如果初学者从未接触过EF 6.x,我们知道EF 6.x默认启用了延迟加载,所以这似乎有点强人所难的意味,在EF Core 2.1对于是否启用延迟加载通过单独提供包的形式来供我们所需,二者相对而言,EF 6.x对于延迟加载的使用是不明确、含糊其辞的,而EF Core 2.1对于延迟加载是很具体、明确的,如此一来至少不会造成滥用的情况。
深入理解EF Core 2.1延迟加载
在我个人公众号发过一篇文章也通过示例讲解了EF Core延迟加载的雏形早就有了,这里再稍微给个示例解释EF Core 2.1之前延迟加载的影子在哪里呢?我们依然给出已经用烂了的两个Blog和Post这两个类,如下:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime ModifiedTime { get; set; }
public byte Status { get; set; }
public bool IsDeleted { get; set; }
public ICollection<Post> Posts { get; set; } = new List<Post>();
}
public class Post
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime ModifiedTime { get; set; } public int? BlogId { get; set; }
public Blog Blog { get; set; } }
接下来我们进行如下查询,我们能够看到此时并未利用Include显式加载Posts,通过如下查询EF Core内部会进行关系修正从而查询出Posts。
var dbContext = new EFCoreDbContext();
var blog = dbContext.Blogs.FirstOrDefault();
var posts = dbContext.Posts.Where(d => d.Blog.Id == blog.Id).ToList();
在EF Core 2.1中我们需要下载【Microsoft.EntityFrameworkCore.Proxies】包,同时在OnConfiguring方法中配置启用延迟加载代理,如下:
除了通过如上配置外导航属性必须用virtual关键字修饰(如上示例类未添加,请自行添加),否则将抛出异常,你懂的。接下来在完全配置好延迟加载的前提下再来进行如下查询,此时在我们需要用到Posts时才会去数据库中查询。
var dbContext = new EFCoreDbContext();
var blog = dbContext.Blogs.FirstOrDefault();
var posts = blog.Posts.ToList();
对于EF Core中的延迟加载和EF 6.x使用方式无异,接下来我们再来看看官网给出了未启用代理也可进行延迟加载,通过安装【Microsoft.EntityFrameworkCore.Abstractions 】包引用ILazyLoader服务进行实现,如下:
public class Blog
{
private ILazyLoader LazyLoader { get; set; } public Blog(ILazyLoader lazyLoader)
{
LazyLoader = lazyLoader;
}
public int Id { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime ModifiedTime { get; set; }
public byte Status { get; set; }
public bool IsDeleted { get; set; } private ICollection<Post> _posts; public ICollection<Post> Posts
{
get => LazyLoader?.Load(this, ref _posts);
set => _posts = value;
}
}
public class Post
{
private ILazyLoader LazyLoader { get; set; }
public Post(ILazyLoader lazyLoader)
{
LazyLoader = lazyLoader;
}
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime ModifiedTime { get; set; } public int? BlogId { get; set; } private Blog _blog;
public Blog Blog
{
get => LazyLoader?.Load(this, ref _blog);
set => _blog = value;
}
}
通过如上注入ILazyLoader服务依附于实体上最终实现延迟加载,这么做对于启用延迟加载代理的最大好处在于只针对特定实体进行延迟加载,而使用延迟加载代理则是全局配置,所有实体都必须通过virtual关键字修饰且都会实现延迟加载。同时呢,通过如下图可知,此时ILazyLoader依附在上下文中也就是说一旦创建实体实例将实现延迟加载。
当然无论是EF 6.x还是EF Core 2.1进行如下查询,那么结果对于如下第二次查询的导航属性将不会再去数据库中查询,因为主体对应的导航属性在内存中已存在,此时将直接返回,也就是说主体查询两次,而依赖实体则将只执行一次查询。
var dbContext = new EFCoreDbContext();
var blog = dbContext.Blogs.FirstOrDefault();
var posts = blog.Posts.ToList(); var blog1 = dbContext.Blogs.FirstOrDefault();
var posts1 = blog1.Posts.ToList();
接下来我们再来看看在上下文实例池中启用延迟加载并结合显式加载看看EF Core执行策略是怎样的呢?
var services = new ServiceCollection();
services.AddDbContextPool<EFCoreDbContext>(options =>
{
var loggerFactory = new LoggerFactory();
loggerFactory.AddConsole(LogLevel.Debug);
options.UseLazyLoadingProxies().UseLoggerFactory(loggerFactory).UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=EFCore2xDb;integrated security=True;MultipleActiveResultSets=True;");
}); var serviceProvider = services.BuildServiceProvider(); var dbContext = serviceProvider.GetRequiredService<EFCoreDbContext>(); var blog = dbContext.Blogs.Include(d => d.Posts).Last();
var posts = blog.Posts.FirstOrDefault(); var blog1 = dbContext.Blogs.FirstOrDefault();
var posts1 = blog1.Posts.FirstOrDefault();
上述查询并结合最终生成的SQL得知:当没有执行显式加载时若我们启用延迟加载则强制执行延迟加载,否则执行显式加载,同时我们通过验证也得知注入ILazyLoader服务后并调用Load方法加载关联实体内部本质则是若要访问的关联实体在内存中不存在时则执行RPC加载关联实体,否则将从内存中获取。
如上所述若我们没有显式进行饥饿加载,那么在启用延迟加载的前提下对于任何关联实体是否都会执行延迟加载呢?比如复杂属性呢?我们再来看看如下示例(请自行在上述配置上下文实例池中启用延迟加载代理)。
public class StreetAddress
{
public string Street { get; set; }
public string City { get; set; }
} public class Order
{
public int Id { get; set; }
public virtual StreetAddress ShippingAddress { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>(e =>
{
e.ToTable("Orders"); e.HasKey(k => k.Id); e.OwnsOne(o => o.ShippingAddress);
});
}
var order = dbContext.Orders.FirstOrDefault();
var shippingAddress = order.ShippingAddress;
我们从如上图生成的SQL得知:对于复杂属性即通过OwnOne配置的复杂属性在查询时,EF Core会一次性将复杂属性值全部返回(也就是说复杂属性值总是会加载),所以对于启用延迟加载不会起到任何作用,即使是通过Include进行显式加载都是多此一举。
延迟加载避免循环引用
无论是EF 6.x还是EF Core 2.1中的延迟加载都无法避免循环引用问题,若在.NET Core Web应用程序中启用了延迟加载,我们需要在ConfigureServices方法中进行如下配置才行。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
}
在写博客期间有一些童鞋在评论中留言问我是如何学习的,每个人学习方式肯定不一样,但是绝对少不了多敲代码,这里就有一个实际例子(这里不是批评那位童鞋哈),有一位童鞋购买了我写的书(首先感谢那位童鞋),看到某一章节问我那里是不是错了,我一看大概就问了那位童鞋是不是没敲代码,个人觉得无论是看技术书还是看技术博客,还是要敲一遍为好,因为那个章节的某一个类是在某一命名空间下的,估计那位童鞋没见过所以以为错了,别光顾着看,多敲敲代码验证验证总没错的。
评论送书规则
6月、19、20、21、22总计4天,在本帖,每天上午10点的第一个回帖评论者,分别赠送本书1本,good luck to u(如果您需要签名留作纪念的话私信我可告知,默认不需要,虽然我字写的很丑)。
同一ID不可以重复参与活动,重复的话,取紧接着的下一个人。不允许用程序刷屏,一旦发现,取消资格。
明确确认您满足以上规则后,请写下您的地址、姓名、邮编、手机号私信给我,以便后续邮寄。
深入了解EntityFramework Core 2.1延迟加载(Lazy Loading)的更多相关文章
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- Entity Framework加载相关实体——延迟加载Lazy Loading、贪婪加载Eager Loading、显示加载Explicit Loading
Entity Framework提供了三种加载相关实体的方法:Lazy Loading,Eager Loading和Explicit Loading.首先我们先来看一下MSDN对三种加载实体方法的定义 ...
- Lazy Loading | Explicit Loading | Eager Loading in EntityFramework and EntityFramework.Core
EntityFramework Eagerly Loading Eager loading is the process whereby a query for one type of entity ...
- EntityFramework 7 更名为EntityFramework Core(预发布状态)
前言 最近很少去学习和探索新的东西,尤其是之前一直比较关注的EF领域,本身不太懒,但是苦于环境比较影响自身的心情,所以迟迟没有下笔,但是不去学习感觉在精神层面缺少点什么,同时也有园友说EF又更新了,要 ...
- EntityFramework Core笔记:查询数据(3)
1. 基本查询 1.1 加载全部数据 using System.Linq; using (var context = new LibingContext()) { var roles = contex ...
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
- EntityFramework Core技术线路(EF7已经更名为EF Core,并于2016年6月底发布)
官方文档英文地址:https://github.com/aspnet/EntityFramework/wiki/Roadmap 历经延期和更名,新版本的实体框架终于要和大家见面了,虽然还有点害羞.请大 ...
- EntityFramework Core 1.1有哪些新特性呢?我们需要知道
前言 在项目中用到EntityFramework Core都是现学现用,及时发现问题及时测试,私下利用休闲时间也会去学习其他未曾遇到过或者用过的特性,本节我们来讲讲在EntityFramework C ...
- EntityFramework 6.x和EntityFramework Core必须需要MultipleActiveResultSets?
前言 本节我们来探讨到底需不需要在连接字符串上加上MultipleActiveResultSets = true ?,若您有更深层次的理解欢迎留下您的脚印. EntityFramework 6.x和E ...
随机推荐
- 试试自行封装AJAX和jQuery中的ajax封装的基本使用
封装的套路: 1.写一个相对比较完善的用例2.写一个空函数,没有形参,将刚刚的用例直接作为函数的函数体3.根据使用过程中的需求抽象函数 代码记录如下: <script> function ...
- 认识音频格式-Au (NeXT/Sun)
音频格式比较多, Au音频格式是一种被sun微处理器公司发明的一种简单的音频编码格式.日后一直在NEXT系统上使用,后面就演变成了一种标准的音频编码格式.目前很多音频设备上都支持这种编码格式.这种编码 ...
- 4.alembic数据迁移工具
alembic是用来做ORM模型与数据库的迁移与映射.alembic使用方式跟git有点类似,表现在两个方面,第一个,alemibi的所有命令都是以alembic开头: 第二,alembic的迁移文件 ...
- .NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.案例结构总览 这里,假设我们有两个客户端(一个Web网站,一个移动App),他们要使用系统,需要通过API网关(这里API网关始终作为 ...
- 【Android Studio安装部署系列】十五、Android studio添加Assets目录
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 Android Studio新建项目时是没有assets目录,需要自己手动创建. app右键——New——Folder——Asset ...
- 学习ASP.NET Core Razor 编程系列十八——并发解决方案
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- spring boot 集成 zookeeper 搭建微服务架构
PRC原理 RPC 远程过程调用(Remote Procedure Call) 一般用来实现部署在不同机器上的系统之间的方法调用,使得程序能够像访问本地系统资源一样,通过网络传输去访问远程系统资源,R ...
- RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2->WinForm版本重构岗位授权管理界面更规范、高效与美观
岗位(职位)管理模块主要是针对组织机构的岗位(职位)进行管理,包括:增加.修改.删除.移动.对岗位设置用户,设置岗位的权限等.岗位管理在企业应用中是一个普遍应用的模块,也属于其他业务应用的基础.合理的 ...
- 搞懂Redis到底快在哪里
前言 Redis是一种基于键值对(Key-Value)的NoSQL数据库,Redis的Value可以由String,hash,list,set,zset,Bitmaps,HyperLogLog等多种数 ...
- leetcode math类型题目解题总结
2. Add Two Numbers https://leetcode.com/problems/add-two-numbers/description/ class Solution { publi ...