EF的延迟加载
什么是延迟加载?
通俗的是说,就是按需要加载,也就是需要数据的时候再加载。EF默认会进行延迟加载
为什么要使用延迟加载?
你的身边是不是有朋友在使用EF开发的时候总是喜欢在每一句的后面加上一个ToList(),
其实这样是不对的!
在每次执行ToList()或者FirstOrDefault()等函数操作时,EF都会去请求一次数据库。
这里说的是数据查询操作,至于CUD这些操作会在SaveChange()时进行数据库的请求。
比如这样一段代码:(仅举例)
var users = EntityTest.Users.Where(u=>u.Adress=="湖北");//过滤地址为湖北的
var userMale = users.Where(u=>u.gender==1).ToList();//过滤出性别为男的
var userFemale = users.Where(u=>u.gender==0).ToList();//过滤出性别为女的
在过滤湖北的这一行,其实并没有进行数据库的请求,只是Where方法将所写的lambda表达式保存为了Sql语句,在进行性别过滤进行ToList()之后才访问了数据库。
好处:用时才加载,保证了数据的实时性,另外在做多条件查询时只要是先拼凑查询语句,最后再执行数据库访问,降低了服务器的负担。
延迟加载的实现:
上面说到,Where方法将所写的lambda表达式保存为了Sql语句,通过智能提示,发现此时users返回的是一个IQueryable类型的数据,并且Where的第一个参数是this前缀,
由此得出Where并不是在IQueryable接口内部的,而是在外部类通过扩展方法的方式加上去的,这个类就是Queryable。
但是为何Where方法是从Entity这个EF上下文对象中点出来的?
通过F2进入EF上下文中的DbSet
因此,EF的延迟加载是依靠Queryable实现的。
Queryable从何而来?
在System.Linq命名空间下,有两个静态类:
①:Enumerable类,它针对继承了IEnumerable
②:Queryable类,它针对继承了IQueryable
IEnumerable
如上所说IQueryable中的Where是将表达式保存为Sql,IEnumerable接口中的Where就是用来过滤本地数据的。
实现步骤:
每次在执行where查询操作符的时候IQueryProvider会为我们创建一个新的IQueryable
得到了一个IEnumerable,所以EF在查询数据时候不要先取IEnumerable再去筛选数据。执行ToList方法时才会去真正调用迭代器GetEnumerator()
取值。真正取值时候,会去执行IQueryProvider中的Excute方法.(解析表达式,然后执行取得结果))
这就是IQueryable的延迟加载