• EF6学习笔记九:初识延迟加载、饥饿加载、显式加载


    要专业系统地学习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;

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

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

    然后我对数据集查询

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

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

    延迟加载(Lazy Loading)

    现在我们就来看延迟加载

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

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

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

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

    var res = db.Orders.FirstOrDefault();

     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]
    复制代码

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

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

    var pro = res.Products.FirstOrDefault();

    生成的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
    复制代码

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

     饥饿加载(Eager Loading)

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

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

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

    生成的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
    复制代码

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

     显式加载(Explicitly Loading)

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

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

    设置Configuration.LazyLoadingEnabled = false;

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

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

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

    行,来显式加载

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

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

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

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

  • 相关阅读:
    mysql
    mysql
    mysql
    mysql
    sed编辑命令
    awk正则应用
    awk运算符
    awk命令细节
    uniq命令
    sort命令
  • 原文地址:https://www.cnblogs.com/anyihen/p/12818871.html
Copyright © 2020-2023  润新知