【Entity Framework】你必须要了解EF中数据查询之数据加载

【Entity Framework】你必须要了解EF中数据查询之数据加载

文章目录

  • 【Entity Framework】你必须要了解EF中数据查询之数据加载
    • 一、概述
    • 二、预先加载
      • 2.1 包含多个层级
      • 2.2 经过筛选的包含
    • 三、显示加载
      • 3.1查询关联实体
    • 四、延时加载
      • 4.1 不使用代理进行延迟加载

在这里插入图片描述

一、概述

Entity Framework Core允许在模型中使用导航属性来加载关联实体。有三种常见的O/RM模式可用于加载关联数据。

  • 预先加载表示从数据库中加载关联数据,作为初始查询的一部分;
  • 显示加载表示稍后从数据库中显示加载关联数据;
  • 延迟加载表示在访问导航属性时,从数据库中以透明方式加载关联数据;

二、预先加载

可以使用Include方法来指定要包含在查询结果中的关联数据。如示例,结果中,结果中返回的blogs将使用关联的posts填充其posts属性。

using (var context = new BloggingContext())
{var blogs = context.Blogs.Include(blog => blog.Posts).ToList();
}

Entity Framework Core 会根据之前已加载到上下文实例中的实体自动填充导航属性。 因此,即使不显式包含导航属性的数据,如果先前加载了部分或所有关联实体,则仍可能填充该属性。

可以在单个查询中包含多个关系的关联数据。

using (var context = new BloggingContext())
{var blogs = context.Blogs.Include(blog => blog.Posts).Include(blog => blog.Owner).ToList();
}

2.1 包含多个层级

使用ThenInclude方法可以依循关系包含多个层级的关联数据。以下示例加载了所有博客,其相关文章及每篇文章的作者。

using (var context = new BloggingContext())
{var blogs = context.Blogs.Include(blog => blog.Posts).ThenInclude(post => post.Author).ToList();
}

可通过链式调用ThenInclude,进一步包含更深级别的关联数据。

using(var context = new BloggingContext())
{var blogs = context.Blogs.Include(blog       => blog.Posts).ThenInclude(post   => post.Author).ThenInclude(author => author.Photo).ToList();
}

可以将对来自多个级别和多个根的关联数据的所有调用合并到同一查询中。

using(var context=new BloggingContext())
{var blogs = context.Blogs.Include(blog       => blog.Posts).ThenInclude(post   => post.Author).ThenInclude(author => post.Photo).Include(blog       => blog.Owner).ThenInclude(owner  => owner.Photo).ToList();
}

你可能希望将已包含的某个实体的多个关联实体都包含进来。 例如,当查询 Blogs 时,你会包含 Posts,然后希望同时包含 PostsAuthorTags。 为了包含这两项内容,需要从根级别开始指定每个包含路径。 例如,Blog -> Posts -> AuthorBlog -> Posts -> Tags。 这并不意味着会获得冗余联接查询,在大多数情况下,EF 会在生成 SQL 时合并相应的联接查询。

using (var context = new BloggingContext())
{var blogs = context.Blogs.Include(blog => blog.Posts).ThenInclude(post => post.Author).Include(blog => blog.Posts).ThenInclude(post => post.Tags).ToList();
}

2.2 经过筛选的包含

在应用包含功能来加载相关数据时,可对已包含的集合导航应用某些可枚举的操作,这样就可以对结果进行筛选和排序。

支持的操作包括:WhereOrderByOrderByDescendingThenByThenByDescendingSkipTake

应对传递到Include方法的Lambda中的集合导航应用这类操作。如下例所示:

using (var context = new BloggingContext())
{var filteredBlogs = context.Blogs.Include(blog => blog.Posts.Where(post => post.BlogId == 1).OrderByDescending(post => post.Title).Take(5)).ToList();
}

可对多次包含的每个导航应用相同的操作:

using (var context = new BloggingContext())
{var filteredBlogs = context.Blogs.Include(blog => blog.Posts.Where(post => post.BlogId == 1)).ThenInclude(post => post.Author).Include(blog => blog.Posts.Where(post => post.BlogId == 1)).ThenInclude(post => post.Tags.OrderBy(postTag => postTag.TagId).Skip(3)).ToList();
}

三、显示加载

可以通过DbContext.Entry(...) API显示加载导航属性。

using(var context=new BloggingContext())
{var blog = Context.Blogs.Single(b=>b.BlogId == 1);context.Entry(blog).Collection(b=>b.Posts).Load();context.Entry(blog).Reference(b => b.Owner).Load();
}

还可以通过执行返回关联实体的单独查询来显式加载导航属性。 如果已启用更改跟踪,则在查询具体化实体时,EF Core 将自动设置新加载的实体的导航属性以引用任何已加载的实体,并设置已加载实体的导航属性以引用新加载的实体。

3.1查询关联实体

可以获得表示导航属性内容的LINQ查询。

这使你可对查询应用其他运算符。示例:

using (var context = new BloggingContext())
{var blog = context.Blogs.Single(b => b.BlogId == 1);var postCount = context.Entry(blog).Collection(b => b.Posts).Query().Count();
}

还可以筛选要加载到内存中的关联实体。

using (var context = new BloggingContext())
{var blog = context.Blogs.Single(b => b.BlogId == 1);var goodPosts = context.Entry(blog).Collection(b => b.Posts).Query().Where(p => p.Rating > 3).ToList();
}

四、延时加载

使用延迟加载的最简单方法是通过安装Microsoft.EntityFrameworkCore.Proxies包,并通过调用UseLazyLoadingProxies来启动该包。

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)=> optionsBuilder.UseLazyLoadingProxies().UseSqlServer(myConnectionString);

或在使用 AddDbContext 时:

.AddDbContext<BloggingContext>(b => b.UseLazyLoadingProxies().UseSqlServer(myConnectionString));

EF Core将为可被重写的任何导航属性启用延迟加载。

public class Blog
{public int Id { get; set; }public string Name { get; set; }public virtual ICollection<Post> Posts { get; set; }
}public class Post
{public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }public virtual Blog Blog { get; set; }
}

4.1 不使用代理进行延迟加载

不使用代理进行延迟加载的工作方式是将 ILazyLoader 注入到实体中,如实体类型构造函数中所述。例如:

public class Blog
{private ICollection<Post> _posts;public Blog(){}private Blog(ILazyLoader lazyLoader){LazyLoader = lazyLoader;}private ILazyLoader LazyLoader { get; set; }public int Id { get; set; }public string Name { get; set; }public ICollection<Post> Posts{get => LazyLoader.Load(this, ref _posts);set => _posts = value;}
}public class Post
{private Blog _blog;public Post(){}private Post(ILazyLoader lazyLoader){LazyLoader = lazyLoader;}private ILazyLoader LazyLoader { get; set; }public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }public Blog Blog{get => LazyLoader.Load(this, ref _blog);set => _blog = value;}
}

此方法不要求实体类型为可继承的类型,也不要求导航属性必须是虚拟的,且允许通过new创建的实体实例在附加到上下文后可进行延迟加载。但它需要对Microsoft.EntityFrameworkCore.Abstractions包中定义的ILazyLoader服务的引用。此包包含所允许的最少的一组类型,以便将依赖此包时所产生的影响将到最低。不过,可以将ILazyLoader.Load方法以委托的形式注入,这样就可以完全避免依赖于实体类型的任何EF Core包。

public class Blog
{private ICollection<Post> _posts;public Blog(){}private Blog(Action<object, string> lazyLoader){LazyLoader = lazyLoader;}private Action<object, string> LazyLoader { get; set; }public int Id { get; set; }public string Name { get; set; }public ICollection<Post> Posts{get => LazyLoader.Load(this, ref _posts);set => _posts = value;}
}public class Post
{private Blog _blog;public Post(){}private Post(Action<object, string> lazyLoader){LazyLoader = lazyLoader;}private Action<object, string> LazyLoader { get; set; }public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }public Blog Blog{get => LazyLoader.Load(this, ref _blog);set => _blog = value;}
}

上述代码使用 Load 扩展方法,以便更干净地使用委托:

public static class PocoLoadingExtensions
{public static TRelated Load<TRelated>(this Action<object, string> loader,object entity,ref TRelated navigationField,[CallerMemberName] string navigationName = null)where TRelated : class{loader?.Invoke(entity, navigationName);return navigationField;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/311549.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑网络一切正常但无法上网-注意检查代理

当电脑出现无法上网&#xff0c; 但是网络适配器又一切正常的时候&#xff0c; 不妨检查一下网络代理设置&#xff0c; 看是否处于开启状态。如果是开启状态&#xff0c; 关闭后再次尝试。 代理服务器自动设置成开启状态&#xff0c; 并且代理地址服务器地址设置成127.0.0.1:1…

提升测试效率都有哪些具体手段?

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

OVITO-2.9版本

关注 M r . m a t e r i a l , \color{Violet} \rm Mr.material\ , Mr.material , 更 \color{red}{更} 更 多 \color{blue}{多} 多 精 \color{orange}{精} 精 彩 \color{green}{彩} 彩&#xff01; 主要专栏内容包括&#xff1a; †《LAMMPS小技巧》&#xff1a; ‾ \textbf…

Matlab|电价型负荷需求响应(考虑电价变化)

程序复现来源于《计及需求响应消纳风电的电-热综合能源系统经济调度 》第四章内容。 一、原理 需求响应的基本原理是需求侧根据电力市场价格和电网要求改变其负荷需求以 获取一定的利益回报。其中 PDR 可通过直观的电价变化信号引导用户调节用电方式&#xff0c; 从而达到优…

JVM结构化体系

目录 目录 1.JVM 简介 1.1. 如何理解 JVM 呢&#xff1f; 1.2. 市场主流 JVM 分析&#xff1f; 1.3. 为什么要学习 JVM&#xff1f; 1.4. 字节码底层是如何执行呢&#xff1f; 如何理解 JIT 呢&#xff1f; 为什么 JVM 中解释执行与编译执行的并存&#xff08;混合模式&…

JavaScript 高性能编程 —— 加载和运行

JavaScript 在浏览器中的性能,可认为是开发者所要面对的最重要的可用性问题。此问题因 JavaScript 的阻塞特征而复杂,也就是说,当 JavaScript 运行时其他的事情不能被浏览器处理。 事实上,大多数浏览 器使用单进程处理 UI 更新和 JavaScript 运行等多个任务,而同一时间只能…

ADB的基本语法及常用命令

学习网址 ADB命令的基本语法如下&#xff1a; adb [-d|-e|-s <serialNumber>] <command> 如果有多个设备/模拟器连接&#xff0c;则需要为命令指定目标设备。 参数及含义如下&#xff1a; 常用命令如下&#xff1a; 1. 启动ADB服务 adb start-server 2. 停止…

OpenHarmony实战开发-Worker子线程中解压文件。

介绍 本示例介绍在Worker 子线程使用ohos.zlib 提供的zlib.decompressfile接口对沙箱目录中的压缩文件进行解压操作&#xff0c;解压成功后将解压路径返回主线程&#xff0c;获取解压文件列表。 效果图预览 使用说明 1.点击解压按钮&#xff0c;解压test.zip文件&#xff0c…

Spring底层如何执行?

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Spring底层如何执行refresh()prepareRefresh() 准备刷新的工作initPropertySources() obtainFreshBeanFactory()refreshBeanFactory()AbstractRefreshableApplicati…

【ensp】VLAN间通信的解决办法

目录 VLAN间通信简介 VLAN间通信的两种方式 借助三层设备路由器进行VLAN间的通信&#xff08;也就是单臂路由&#xff09; 在端口上创建子接口之后为什么需要开启arp广播&#xff0c;是因为他是子接口吗? 拓扑图 交换机配置 路由器配置 查看路由器配置 测试能否实现…

Element-Ui的Form表单:Label文本两端对齐,且必填项的*不影响布局

1. HTML 结构 首先&#xff0c;确保你的 HTML 或 Vue 模板中有一个 el-form 组件&#xff0c;类似下面这样&#xff1a; <div id"app"><el-form :model"form" label-width"100px"><el-form-item label"用户名">&l…

基于springboot的医护人员排班系统

随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了医护人员排班系统的开发全过程。通过分析医护人员排班系统管理的不足&#xff0c;创建了一个计算机管理医护人员排班系统的方案。文章介绍了医护人员排班系统的系统分…

更改ip地址的几种方式有哪些

在数字化时代&#xff0c;IP地址作为网络设备的标识&#xff0c;对于我们在网络世界中的活动至关重要。然而&#xff0c;出于多种原因&#xff0c;如保护隐私、访问特定网站或进行网络测试&#xff0c;我们可能需要更改IP地址。虎观代理将详细介绍IP地址的更改方法与步骤&#…

【JavaSE】你真的了解内部类吗?

前言 本篇会详细讲解内部类的四种形式&#xff0c;让你掌握内部类~ 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 前言 内部类介绍 实例内部类 定义 调用 静态内部类 定义 调用 匿名内部类 定义和调用1 调用方法2 …

预分频器×重装载值)/LSI频率 为什么等于总时间

1. 第一种算法理解&#xff1a;分频系数 64 &#xff0c;外部低速时钟40khz&#xff0c; 则一次计数周期1.6ms &#xff0c;计数625个数&#xff0c;则有625个周期 &#xff0c;1.6ms*625 等于1s 如果分频系数是64&#xff0c;外部低速时钟&#xff08;LSI&#xff09;频率是…

gitee和idea集成

1 集成插件 2 配置账号密码 3 直接将项目传到仓库 4直接从gitee下载项目

【CAN】采样点介绍及测试方法

文章目录 1 什么是采样点2 为什么需要采样点3 采样点的计算公式4 VH6501测试原理和方法4.1 VH6501测试采样点原理4.2 VH6501测试方法 >>返回总目录<< 1 什么是采样点 采样点是节点判断信号逻辑电平的位置&#xff0c;是CAN控制器读取总线电平&#xff0c;并解释各…

前端console用法分享

console对于前端人员来讲肯定都不陌生&#xff0c;相信大部分开发者都会使用console来进行调试&#xff0c;但它能做的绝不仅限于调试。 最常见的控制台方法 作为开发者&#xff0c;最常用的 console 方法如下&#xff1a; 控制台打印结果&#xff1a; 今天我分享的是一些 co…

网络爬虫:定义、应用及法律道德考量

网络爬虫技术在当今数据驱动的世界中发挥着重要作用。本文将从网络爬虫的定义和主要功能&#xff0c;其在业界的应用实例&#xff0c;以及涉及的法律和道德问题三个方面进行深入探讨。 1. 爬虫的定义和主要功能 网络爬虫&#xff0c;也称为网页爬虫或蜘蛛&#xff0c;是一种…

【C++对于C语言的扩充】函数重载、引用以及内联函数

文章目录 &#x1f680;前言&#x1f680;函数重载注意&#xff1a;✈️为什么C可以实现函数重载&#xff0c;而C语言却不行呢&#xff1f; &#x1f680;引用✈️引用的特性✈️C中为什么要引入引用✈️引用与指针的区别 &#x1f680;内联函数✈️内联函数特性 &#x1f680;…