前言

接下来会陆续详细讲解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)的更多相关文章

  1. 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制

    你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...

  2. Entity Framework加载相关实体——延迟加载Lazy Loading、贪婪加载Eager Loading、显示加载Explicit Loading

    Entity Framework提供了三种加载相关实体的方法:Lazy Loading,Eager Loading和Explicit Loading.首先我们先来看一下MSDN对三种加载实体方法的定义 ...

  3. 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 ...

  4. EntityFramework 7 更名为EntityFramework Core(预发布状态)

    前言 最近很少去学习和探索新的东西,尤其是之前一直比较关注的EF领域,本身不太懒,但是苦于环境比较影响自身的心情,所以迟迟没有下笔,但是不去学习感觉在精神层面缺少点什么,同时也有园友说EF又更新了,要 ...

  5. EntityFramework Core笔记:查询数据(3)

    1. 基本查询 1.1 加载全部数据 using System.Linq; using (var context = new LibingContext()) { var roles = contex ...

  6. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  7. EntityFramework Core技术线路(EF7已经更名为EF Core,并于2016年6月底发布)

    官方文档英文地址:https://github.com/aspnet/EntityFramework/wiki/Roadmap 历经延期和更名,新版本的实体框架终于要和大家见面了,虽然还有点害羞.请大 ...

  8. EntityFramework Core 1.1有哪些新特性呢?我们需要知道

    前言 在项目中用到EntityFramework Core都是现学现用,及时发现问题及时测试,私下利用休闲时间也会去学习其他未曾遇到过或者用过的特性,本节我们来讲讲在EntityFramework C ...

  9. EntityFramework 6.x和EntityFramework Core必须需要MultipleActiveResultSets?

    前言 本节我们来探讨到底需不需要在连接字符串上加上MultipleActiveResultSets = true ?,若您有更深层次的理解欢迎留下您的脚印. EntityFramework 6.x和E ...

随机推荐

  1. ng跳转映射,被阿里云的云盾拦截,提示备案问题分析

    在一个云项目调试过程中,ng映射到云时,发现被云盾拦截,提示备案. 1.客户提供的二级域名已经在华为云备案,映射的主机部署在阿里云. 2.ng映射域名时,出现备案提醒,f12调试发现跳转时,被拦截了. ...

  2. Entity Framework 之存储过程篇

    最近几天在搞CRUD,使用的是EF这个ORM,最近的项目中上了存储过程,就把在开发中的经验分享出来!我们先创建一个最基本的存储过程,脚本如下,这是一个不带参数的存储过程,我们从最简单的往上走! cre ...

  3. 深入浅出mongoose

    深入浅出mongoose mongoose是nodeJS提供连接 mongodb的一个库. 此外还有mongoskin, mongodb(mongodb官方出品). 本人,还是比较青睐mongoose ...

  4. Python自省

    自省就是通过一定机制查询到对象的内部结构,也就是运行时获取对象内部的属性以及类型,在Python中dir(),type(), hasattr(), isinstance()都是很好的自省例子 #!/u ...

  5. ASP.NET Core 使用 Google 验证码(reCAPTCHA v3)代替传统验证码

    写在前面 友情提示: Google reCAPTCHA(v3下同) 的使用不需要"梯子",但申请账号的时候需要! Google reCAPTCHA 的使用不需要"梯子&q ...

  6. SpringBoot技术栈搭建个人博客【前台开发/项目总结】

    前言:写前台真的是我不擅长的东西...所以学习和写了很久很久...前台页面大概开发了两天半就开发好了,采用的静态的html和bootstrap来写,写后台的时候纠结住了...怎么说呢,写页面真的是头疼 ...

  7. java内存溢出的情况解决方法

    内存溢出虽然很棘手,但也有相应的解决办法,可以按照从易到难,一步步的解决. 第一步,就是修改JVM启动参数,直接增加内存.这一点看上去似乎很简单,但很容易被忽略.JVM默认可以使用的内存为64M,To ...

  8. Mac下安装多版本python

    1.安装Homebrew 将命令行复制至终端,进行安装. /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/H ...

  9. 从官方文档去学习之FreeMarker

    一.前言 上一篇 <从现在开始,试着学会用官方文档去学习一个技术框架>提倡大家多去从官方文档学习技术,没有讲到具体的实践,本篇就拿一个案例具体的说一说,就是FreeMarker,选择这个框 ...

  10. 持续交付之软件包管理maven篇

    背景 持续交付的我们常见的流程如下,其中有一个环节就是软件包管理 今天我们以maven仓库为示例,如下是Jenkins与CD生态: 持续交付的示例 5 Principles 五个原则 Deliver ...