EF 三种加载方式
一、定义
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);
}
}