博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
EF6学习笔记九:初识延迟加载、饥饿加载、显式加载
阅读量:4576 次
发布时间:2019-06-08

本文共 4305 字,大约阅读时间需要 14 分钟。

要专业系统地学习EF前往《你必须掌握的Entity Framework 6.x与Core 2.0》这本书的作者(汪鹏,Jeffcky)的博客:https://www.cnblogs.com/CreateMyself/

EF数据加载三种方式:延迟加载、饥饿加载、显示加载

每种加载方式都有其应用场景,应用不当会导致性能问题

我刚刚有点整懵了,目前算是有点明白,现在只是初步了解一下,把我刚刚搞的东西整理一下

延迟加载(Lazy Loading) 和淘宝的商品列表一样,下拉刷新,按需加载

饥饿加载 (Eager Loading) 加载父对象时同时加载子对象

显式加载 (Explicitly Loading)当我们禁用了延迟加载,仍然可以通过显式加载来延迟加载相关实体

EF中默认是开启延迟加载,那么我们怎么知道自己的查询是延迟加载呢?办法就是查询EF生成的SQL语句,他什么时候生成SQL语句,在什么时候执行查询。

要追踪SQL命令的执行,在SQL server数据库管理工具里面-->工具-->SQL Server Porfiler,这东西不错

我们也可以用一个更简单的方式,EF上下文有个Database.Log Action<string>类型的属性

如果是控制台项目,那么可以讲Console.WriteLine赋值给他,然后当有SQL执行,会为我们打印一些信息

db.Database.Log = Console.WriteLine;
View Code

我自定义了一个打印方法,可以说是没什么意义

db.Database.Log = MyConsole;public static void MyConsole(string str)        {            Console.WriteLine($"四海的跟踪:{str}");        }
View Code

然后我对数据集查询

using (EFDbContext db = new EFDbContext())            {db.Database.Log = MyConsole;                var res = db.Orders.FirstOrDefault();}
View Code

然后我们看看打印了什么东西

延迟加载(Lazy Loading)

现在我们就来看延迟加载

我有两个model,Order订单类和Product产品类,一对多,一个订单包含多产品

现在延迟加载是显式开启的

public class EFDbContext:DbContext    {        public EFDbContext()        {            //  延迟加载  true:开启,false:关闭            Configuration.LazyLoadingEnabled = true;            //Configuration.AutoDetectChangesEnabled = false;        }}
View Code

然后查询订单集合中的第一个订单

var res = db.Orders.FirstOrDefault();
View Code

 EF生成并执行了一条SQL语句

SELECT TOP (1)    [c].[Id] AS [Id],    [c].[OrderNO] AS [OrderNO],    [c].[Description] AS [Description],    [c].[AddTime] AS [AddTime]    FROM [dbo].[tb_Orders] AS [c]
View Code

可以看到EF仅对Oders表进行了查询,没有查询该订单包含的产品

好,我现在要使用订单中的产品数据了,于是,我查询该订单的第一条产品

var pro = res.Products.FirstOrDefault();
View Code

生成的SQL语句如下

SELECT    [Extent1].[Id] AS [Id],    [Extent1].[Name] AS [Name],    [Extent1].[Price] AS [Price],    [Extent1].[Unit] AS [Unit],    [Extent1].[FK_Order_Id] AS [FK_Order_Id],    [Extent1].[AddTime] AS [AddTime]    FROM [dbo].[tb_Products] AS [Extent1]    WHERE [Extent1].[FK_Order_Id] = @EntityKeyValue1
View Code

这就是延迟查询了,当我用的时候才执行查询

 饥饿加载(Eager Loading)

你不使用延迟加载那就使用饥饿加载,显示加载也是属于延迟加载,我一次性拿到所有的数据。饥饿查询使用Include()方法

现在我们查询订单集合中的第一个订单,并且要求包含的产品集合都给我

db.Orders.Include("Products").FirstOrDefault();
View Code

生成的SQL语句如下,很多

:SELECT    [Project2].[C1] AS [C1],    [Project2].[Id] AS [Id],    [Project2].[OrderNO] AS [OrderNO],    [Project2].[Description] AS [Description],    [Project2].[AddTime] AS [AddTime],    [Project2].[C2] AS [C2],    [Project2].[Id1] AS [Id1],    [Project2].[Name] AS [Name],    [Project2].[Price] AS [Price],    [Project2].[Unit] AS [Unit],    [Project2].[FK_Order_Id] AS [FK_Order_Id],    [Project2].[AddTime1] AS [AddTime1]    FROM ( SELECT        [Limit1].[Id] AS [Id],        [Limit1].[OrderNO] AS [OrderNO],        [Limit1].[Description] AS [Description],        [Limit1].[AddTime] AS [AddTime],        [Limit1].[C1] AS [C1],        [Extent2].[Id] AS [Id1],        [Extent2].[Name] AS [Name],        [Extent2].[Price] AS [Price],        [Extent2].[Unit] AS [Unit],        [Extent2].[FK_Order_Id] AS [FK_Order_Id],        [Extent2].[AddTime] AS [AddTime1],        CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]        FROM   (SELECT TOP (1)            [Extent1].[Id] AS [Id],            [Extent1].[OrderNO] AS [OrderNO],            [Extent1].[Description] AS [Description],            [Extent1].[AddTime] AS [AddTime],            1 AS [C1]            FROM [dbo].[tb_Orders] AS [Extent1] ) AS [Limit1]        LEFT OUTER JOIN [dbo].[tb_Products] AS [Extent2] ON [Limit1].[Id] = [Extent2].[FK_Order_Id]    )  AS [Project2]    ORDER BY [Project2].[Id] ASC, [Project2].[C2] ASC
View Code

然后我们把这段SQL拿到数据执行看一下

 

 显式加载(Explicitly Loading)

 显式加载,如果关闭了延迟查询,还可以用显式加载来延迟加载实体。那为什么要弄这么个东西出来呢。可能就是因为延迟加载的问题,使用不当会造成性能问题,具体的性能问题,我现在还没有太多认识。

我们先来看看,关闭延迟加载后,然后用延迟加载的方式来查询会是什么结果。

设置Configuration.LazyLoadingEnabled = false;

查询订单集合的第一个订单,查询该订单的第一个产品

var res = db.Orders.FirstOrDefault();                var pro = res.Products.FirstOrDefault();
View Code

查询订单有SQL语句,当查询产品就报错了,因为产品是null

行,来显式加载

通过DbEntityEntry<T>.Reference("").Load();加载实体

通过DbEntityEntry<T>.Collection("").Load();加载集合

var res = db.Orders.FirstOrDefault();                db.Entry(res).Collection(x =>x.Products).Load();
View Code

 

 第一句只会对Order查询,第二句查询订单中的产品,这样就行了

 

转载于:https://www.cnblogs.com/jinshan-go/p/10272763.html

你可能感兴趣的文章
子节点填充父元素除去一固定高度后的剩余高度
查看>>
[原]IOS 后台发送邮件
查看>>
(转)JAVA Calendar详解
查看>>
转: 编码,charset,乱码,unicode,utf-8与net简单释义
查看>>
C#--正则匹配
查看>>
5.30 考试修改+总结
查看>>
BA-设计施工调试流程
查看>>
C#-CLR各版本特点
查看>>
css3背景透明文字不透明
查看>>
《java JDK7 学习笔记》之接口与多态
查看>>
LeetCode 96:Unique Binary Search Trees
查看>>
kernel-char设备的建立
查看>>
DVWA-CSRF
查看>>
ubuntu common software introduction
查看>>
资源相互引用时 需添加 PerformSubstitution=True
查看>>
MapRedece(单表关联)
查看>>
蒲公英App开发之检测新版本
查看>>
【安卓基础】倒计时按钮封装(验证码倒计时按钮)
查看>>
configparser模块
查看>>
SelectQueryBuilder的用法
查看>>