EF性能之关联加载
鱼和熊掌不能兼得
——中国谚语
一、介绍#
Entity Framework作为一个优秀的ORM框架,它使得操作数据库就像操作内存中的数据一样,但是这种抽象是有性能代价的,故鱼和熊掌不能兼得。但是,通过对EF的学习,可以避免不必要的性能损失。本篇只介绍关联实体的加载的相关知识,这在我之前的文章中都有介绍。
我们已经了解到EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit Loading都是延迟加载。
(一)Lazy Loading使用的是动态代理,默认情况下,如果POCO类满足以下两个条件,EF就使用Lazy Loading:
- POCO类是Public且不为Sealed。
- 导航属性标记为Virtual。
关闭Lazy Loading,可以将LazyLoadingEnabled设为false,如果导航属性没有标记为virtual,Lazy Loading也是不起作用的。
(二)Eager Loading使用Include方法关联预先加载的实体。
(三)Explicit Loading使用Entry方法,对于集合使用Collection,单个实体则使用Reference。
二、实例#
下面通过实例来理解这几种加载方式。
有下面三个实体:Province,City,Governor,一个Province有多个City,并且只有一个Governor。
1: public class Province
2: {
3: public int Id { get; set; }
4: public string Name { get; set; }
5:
6: public virtual Governor Governor { get; set; }
7:
8: public virtual List<City> Cities { get; set; }
9: }
10:
11: public class City
12: {
13: public int Id { get; set; }
14: public string Name { get; set; }
15: }
16:
17:
18: public class Governor
19: {
20: public int Id { get; set; }
21: public string Name { get; set; }
22: }
Lazy Loading
1: private static void LazyLoading(EFLoadingContext ctx)
2: {
3: //发送一条查询到数据库,查询所有的province
4: var list = ctx.Provines.ToList();
5: foreach (var province in list)
6: {
7: //每次遍历(用到导航属性时)都发送2条查询,一条查询当前province包含的city和另一条查询当前province的governor
8: //如果ctx.Configuration.LazyLoadingEnabled为false或者前者为true,但是导航属性没有标注为virtual,下面的操作都会抛出异常
9: Print(province);
10: }
11: }
Eager Loading
1: private static void EagerLoading(EFLoadingContext ctx)
2: {
3: //发送一条查询到数据库库,查询所有的province并关联city和governor
4: var list = ctx.Provines.Include(t => t.Cities).Include(t => t.Governor);
5: foreach (var province in list)
6: {
7: //不管ctx.Configuration.LazyLoadingEnabled为false,还是没有标注导航属性virtual,都不会抛出异常
8: Print(province);
9: }
10: }
Explicti Loading
1: private static void ExplicitLoading(EFLoadingContext ctx)
2: {
3: //发送一条查询到数据库,查询所有的province
4: var list = ctx.Provines.ToList();
5: foreach (var province in list)
6: {
7: var p = ctx.Entry(province);
8: //发送一条查询,查询所有当前province的city
9: p.Collection(t => t.Cities).Load();
10: //发送一条查询,查询当前province的governor
11: p.Reference(t => t.Governor).Load();
12: //不管ctx.Configuration.LazyLoadingEnabled为false,还是没有标注导航属性virtual,都不会抛出异常
13: Print(province);
14: }
15: }
Print方法
1: private static void Print(Province province)
2: {
3: Console.WriteLine("省:【{0}】,市:【{1}】,省长:【{2}】", province.Name, string.Join(",", province.Cities.Select(t => t.Name)), province.Governor.Name);
4: }
三、总结#
关于关联加载实体基本上就是这些内容吧,如果想看这部分详细的介绍,可以参考我这篇文章的后半部分。总的来说,这部分比较简单,一个LazyLoadingEnabled设置,三种加载方式。Lazy Loading会生成大量的sql,Eager Loading生成的关联查询比较负责,Explicit Loading同Lazy Loading一样生成很多的sql,但是有一些其他优点,比如:导航属性可以不用标注为virtual。如果这几种关联都不能解决实际问题,可以直接使用sql查询。
最后附上本文的demo,下载地址:http://pan.baidu.com/s/1i3IAiNF
作者:程序旅途
出处:https://www.cnblogs.com/nianming/p/3494781.html
版权:本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库