EF 三种加载方式 一、定义 二、通过日志查看ef执行过程中的语句 三、延迟加载、懒加载(Lazy Loading) 四、立即加载、贪婪加载、预加载(Eager Loading) 五、显示加载(Explicit Loading) 一、定义 EF数据加载三种方式:延迟加载、饥饿加载、显示加载(EF中默认是开启延迟加载) 延迟加载(Lazy Loading) 和淘宝的商品列表一样,下拉刷新,按需加载。 饥饿加载 (Eager Loading) 加载父对象时同时加载子对象。 显式加载 (Explicitly Loading)当我们禁用了延迟加载,仍然可以通过显式加载来延迟加载相关实体。 二、通过日志查看ef执行过程中的语句 WebCenterContext db = new WebCenterContext(); // 监听日志,将与数据库之间的每一步操作都会打印出来 db.Database.Log =s=> { DataOperate.Logs.LogsWrite.WriteLogToFile("EF_SQL",s,""); }; 三、延迟加载、懒加载(Lazy Loading) 特别注意:关闭延迟加载后,查询主表数据时候,主表的中从表实体为null。 全局配置:在数据库上下文的构造方法中添加 this.Configuration.LazyLoadingEnabled = true; 也可以在使用的时候单独配置。 延迟加载 true:开启,false:关闭,默认就是延迟加载的。 延迟加载的数据在使用的时候才会加载出来,在循环遍历数据的时候建议使用延迟加载。 每次调用子实体(外键所在的实体)的时候,才去查询数据库. 主表数据加载的时候,不去查询外键所在的从表。 需要满足的条件: ①:poco类是public且不能为sealed; ②:关联属性需要标记为Virtual; 开启延迟加载的状态: using (WebCenterContext db = new WebCenterContext()) { db.Database.Log = Console.WriteLine; //EF默认就是延迟加载,默认下面的语句就是true,所以下面语句注释没有任何影响 //db.Configuration.LazyLoadingEnabled = true; var list = db.UserInfo.ToList(); //此处加载的数据,根据监测得出结论,没有对从表进行任何查询操作 foreach (var user in list) { Console.WriteLine("编号:{0},姓名:{1}", user.Code, user.Name); //下面调用导航属性(一对一的关系) 每次调用时,都要去查询数据库(查询从表) var login = user.LoginInfo; Console.WriteLine("登陆时间:{0},IP地址:{1}", login.LoginTime, login.IP); } } 关闭延迟加载的状态: using (WebCenterContext db = new WebCenterContext()) { try { db.Database.Log = Console.WriteLine; //下面的语句为关闭延迟加载 db.Configuration.LazyLoadingEnabled = false; var list = db.UserInfo.ToList(); //关闭延迟加载后,此处从表实体LoginInfo为null,后面不会再次查询了 foreach (var user in list) { Console.WriteLine("学生编号:{0},学生姓名:{1}", user.Code, user.Name); //login 为null,不会再次查询数据库,所以此处报错 var login = user.LoginInfo; Console.WriteLine("登陆时间:{0},IP地址:{1}", login.LoginTime, login.IP); } } catch (Exception ex) { Console.WriteLine(ex.Message); } } 四、立即加载、贪婪加载、预加载(Eager Loading) 使用步骤: ①:先关闭延迟加载:db.Configuration.LazyLoadingEnabled = false; ②:查询主表的同时通过Include把从表数据也查询出来; 由于查询主表的时候通过Include已经一次性将数据查询了出来,所以在调用从表数据的时候,均从缓存中读取,无须查询数据库。 using (WebCenterContext db = new WebCenterContext()) { db.Database.Log = Console.WriteLine; //1.关闭延迟加载 db.Configuration.LazyLoadingEnabled = false; //2. 获取主表数据的同时,通过Include将从表中的数据也全部加载出来 var list = db.UserInfo.Include("LoginInfo").ToList(); foreach (var user in list) { Console.WriteLine("编号:{0},姓名:{1}", user.Code, user.Name); //这里获取从表中的数据,均是从缓存中获取,无需查询数据库 var login = user.LoginInfo; Console.WriteLine("登陆时间:{0},IP地址:{1}", login.LoginTime, login.IP); } } 五、显示加载(Explicit Loading) 关闭延迟加载后,单纯查询主表的数据,后面又想再次查询从表,这个时候就需要用到显示加载了。 前提: ①:关闭了延迟加载:db.Configuration.LazyLoadingEnabled = false; ②:单纯查询了主表,没有使用Include函数关联查询从表; 使用步骤: ①:单个实体用:Reference; ②:集合用:Collection; ③:最后需要Load一下; using (WebCenterContext db = new WebCenterContext()) { db.Database.Log = Console.WriteLine; //1.关闭延迟加载 db.Configuration.LazyLoadingEnabled = false; //2.此处加载的数据,不含从表中的数据 var list = db.UserInfo.ToList(); foreach (var user in list) { Console.WriteLine("编号:{0},姓名:{1}", user.Code, user.Name); //3.下面的这句话,可以开启重新查询一次数据库 //3.1 单个属性的情况用Refercence db.Entry<UserInfo>(user).Reference(c => c.LoginInfo).Load(); //3.2 集合的情况用Collection //db.Entry<UserInfo>(user).Collection(c => c.LoginInfo).Load(); //下面调用关联属性(一对一的关系) 每次调用时,都要去查询数据库 var login = a.LoginInfo; Console.WriteLine("登陆时间:{0},IP地址:{1}", login.LoginTime, login.IP); } }