EF中延迟加载的那些事

延迟加载又称懒加载,通俗一点就是关联了一个对象,不用的时候不去查这个对象,当调用的时候再组织sql去查出这个对象的相关内容。

一.在使用EF时,我们会发现借助于框架生成的实体类中的的导航属性通常是标记 virtual的,这是为何呢?

 二.让我们通过几个例子来发现其中的奥秘

下面的代码是通用的查询,先是打印了查询生成的sql,接着查询出一个Employee对象并带出对应的Dempartment对象。

       using (DemoEntities db = new DemoEntities())
            {
                db.Database.Log = sql => Console.WriteLine(sql);
                Employee emp = db.Employees.FirstOrDefault();
                Console.WriteLine(emp.Name);
                Console.WriteLine(emp.Department.Name);    
            }

   1.导航属性上有virtual的情况下查询两条sql,一条是查出Employee另一条是查Dempartment

 2.现在我们将默认的导航属性中的virtual去掉会发生什么呢,让我们带着疑惑继续往下看

三.原理探究

看到这是不是感觉很怪异喽,加上virtual就能正常执行,去掉就不行了么。这是啥原理呢

1.我们把代码修改一下

     using (DemoEntities db = new DemoEntities())
            {
                Employee emp = db.Employees.FirstOrDefault();
                Console.WriteLine(emp.GetType());  //打印emp的类型
                Console.WriteLine(emp.GetType().BaseType);  //打印emp类型对应的父类
                Console.WriteLine(emp.Name);
                Console.WriteLine(emp.Department.Name);
            }

在原有的基础上我们打印了一下对应对象的类型

2.我们还是先看看默认有virtual的情况

 通过执行代码我们发现,我们所声明的Employee的对象的类型竟然不是Employee而是一个名字特别长的另一个对象,而这个对象的父类才是Employee

3.我们将导航属性的virtual去掉再执行代码看看有什么变化

 看到这里的差异,我们似乎发现了点什么。先说说virtual关键字吧,virtual是虚方法,通常是用于子类的重写。那么这里我们不难推测当导航属性有virtual关键字时,EF帮我们生成了一个

父类是Employee名字老长老长的那个类,在这个类的实现中,重写了一下,当Department为空时,它会去数据库里查一下这个Department对象,所以加上virtual关键字时就会对应两条sql

类似效果如下所示

    class Employee_515EB7DF3C6168BFE9566BD863543E3AED9398AFF473BAB129D9B32823D6E8A3 : Employee {
            private Department _department;
            public override Department Department
            {
                get
                {
                    if (_department==null)
                    {
                        //去数据库中查询Department的信息
                    }
                    return _department;
                }
            }
        }
原文地址:https://www.cnblogs.com/HTLucky/p/13335031.html