第五节: EF高级属性(一) 之 本地缓存、立即加载、延迟加载(不含导航属性)

一. 本地缓存

   从这个章节开始,介绍一下EF的一些高级特性,这里介绍的首先介绍的EF的本地缓存,在前面的“EF增删改”章节中介绍过该特性(SaveChanges一次性会作用于本地缓存中所有的状态的变化),在这里介绍一下本地缓存的另外一个用途。

  ① Find方法通过主键查询数据,主键相同的查询,只有第一次访问数据库,其它均从缓存中读取。

  ② 延迟加载的数据,在第一次使用的使用时访问数据库,后面无论再使用多少次,均是从内存中读取了。

1             Console.WriteLine("--------------------------- 1.本地缓存属性   ------------------------------------");
2                 db.Database.Log += c => Console.WriteLine(c);
3                 //以下4个根据主键id查询,查询了一次,都存到本地缓存里了,所以user2不查询数据库,但user3的id不同,所以查询数据库
4                 var user1 = db.Set<TestInfor>().Find("2");
5                 var user2 = db.Set<TestInfor>().Find("2");
6                 var user3 = db.Set<TestInfor>().Find("3");

二. 立即加载

  这里的立即加载指单表,不含主外键的情况。

  所谓的立即加载就是代码执行的时候直接去数据库查询,与是否立即使用无关,查出来后放到本地缓存里,以后再次使用的时候,从本地缓存中读取。

  常见的立即加载的的标记:toList() 、FirstOrDefault() 。

1         Console.WriteLine("--------------------------- 2.即时加载   ------------------------------------");
2 
3                 ////以下3个属于立即查询,所以每次都要查询数据库,不缓存
4                 var user5 = db.Set<TestInfor>().Where(u => u.id == "2").FirstOrDefault();
5                 var user6 = db.Set<TestInfor>().Where(u => u.id == "2").FirstOrDefault();
6                 var user7 = db.Set<TestInfor>().Where(u => u.id == "2").FirstOrDefault();

三. 延迟加载

这里的延迟加载指单表,不含主外键的情况。

1. 定义:只有我们需要数据的时候,才去数据库查询

  比如:我们需要根据条件判断,通过Where来拼接条件(IQueryable),在拼接的过程中,并没有访问数据库,只有在最终使用的时候,才访问数据库。

  特别注意:调用的时候要foreach循环来调用,只有第一次使用的时候去访问数据库,其它的都是从本地缓存中读取。

2. 禁用延迟加载的方法:

a:如果结果是集合,在拼接的结尾加 toList() ,其它类型调用其它方法

b:如果结果是单个实体,在拼接的结尾加 FirstOrDefault()

3. 好处:保证了数据的实时性,什么时候用,什么时候查询

4. 弊端:每用一次,就需要查询一次数据,服务器压力大

5. 延迟加载的实际开发场景:

分页要要经历where多个条件查询、skip、take、toList,如果每调用一个方法都连接一个数据库,那么在拼接过程中就访问了3次数据库,而且可能数据量非常多,所以这个时候使用延迟加载,只有在所有sql语句拼接完的最后一步才连接数据库。

总结:只要查询结果实现了IQueryable接口类的,那么查询结果都是延迟加载的。

 1           Console.WriteLine("--------------------------- 3.延迟加载   ------------------------------------");
 2                 IQueryable<TestInfor> user4 = db.Set<TestInfor>().Where(u => u.id != "123");
 3                 IQueryable<TestInfor> user6 = db.Set<TestInfor>().Where(u => u.id != "123");
 4                 foreach (var item in user4)
 5                 {
 6                     Console.WriteLine("我要从数据库中读取数据了:" + item.txt1);
 7                 }
 8                 foreach (var item in user4)
 9                 {
10                     Console.WriteLine("我要从数据库中读取数据了2:" + item.txt1);
11                 }
12                 foreach (var item in user6)
13                 {
14                     Console.WriteLine("我要从数据库中读取数据了3:" + item.txt1);
15                 }

延迟加载上述案例分析:

* IQueryable类型的 user4和user6, 都是延迟加载的,下面foreach第一次使用该对象的时候去数据库查询。

* 这里会有这么几个问题:

* ①:foreach第一次遍历的时候去数据库中查询user4,然后放到本地缓存里,后面无论循环多少次,都是从本地缓存中读取user4。

* ②:前两个foreach操控的对象都是user4,所以第二个foreach无论哪次循环,都是从本地缓存中读取

* ③:第三个foreach操控的对象是user6,同样是在foreach第一次循环的时候去数据库查询,所以在代码执行到第一个或第二个foreach的时候,

* 手动去数据库改数据,当执行到第三个foreach,查询出来的数据就是修改后的了。

 

posted @ 2017-10-20 20:56  Yaopengfei  阅读(2473)  评论(0编辑  收藏  举报