想熟练正确的使用EF框架,那么就必须要了解EF加载数据的方式。EF加载数据的方式,小编了解的有预加载、延迟加载、显式加载、按需加载。不同的加载方式都有不同的适用情况,我们不能在这里笼统地下决定说哪种方式好哪种方式不好。但有一点是需要遵循的,那就是如何提高数据加载的效率。今天这篇博客就来介绍一下EF 的预加载和延迟加载。
延迟加载(Lazy Loading)
延迟加载又叫惰性加载(Lazy Loading):即在需要或者使用的时候加载数据。默认情况下,EF会使用延迟加载方式加载数据,即数据库上下文的属性:Configuration.LazyLoadingEnabled = true; 下面通过具体的实例观察一下延迟加载的效果。关于如何建立EF的项目就不再叙述了,可以参考博客:
EF学习和使用(一)Database First
EF学习和使用(二)ModelFirst
EF学习和使用(三)Code First
在下面的代码中,首先会执行一次查询,并将返回的结果存放在变量customers 中。而foreach循环会在每一次循环过程中独立进行一次查询,所以,如果数据库表Customer中有100条记录,那么整个过程将产生101次查询。
using (var dbcontext= new ModelFirstDemoEntities())
{
#region 延迟加载:用的时候加载
var customers = from c in dbcontext.Customer
select c;
foreach (var cus in customers)
{
Console.WriteLine(cus.Id);
foreach (var order in cus.Order) //根据导航属性,自动查询客户的订单
{
Console.WriteLine(order.OrderContent);
}
}
#endregion
}
下面是程序执行的结果以及在SQL Server Profiler中的跟踪记录。可以清楚地看到,对表Customer只进行了一次查询,由于该表只有7条记录,于是在循环中又分别产生了7次对表Order的查询。
如果将数据库上下文的属性设置为 false 的话(Configuration.LazyLoadingEnabled = false; )将不会查询到从表的数据,只会执行一次查询。
预加载(Eager Loading)
如果你想让所有数据一次性全部加载到内存中,那么你需要使用.Include(Entity)方法。看下面的代码,
using (var dbcontext= new ModelFirstDemoEntities())
{
#region 贪婪加载: 一次查询加载全部数据
var q = from t in dbcontext.Customer.Include("Order")
select t;
foreach (var cus in q)
{
Console.WriteLine("Teacher : {0}", cus.Id);
Console.WriteLine("Respective Courses...");
foreach (var order in cus.Order)
{
Console.WriteLine("Course name : {0}", order.OrderContent);
}
Console.WriteLine();
}
#endregion
}
如果你查看SQl Server Profiler中的跟踪信息,你会发现只有一次数据交互过程,即程序只通过一次查询便获取到了所有需要的数据。它也可以减少程序与数据库的交互次数。不过仍然有缺点,那就是如果数据量较大,一次性将所有数据载入内存往往并不是最明智的选择。.Include(Entity)方法允许级联使用,你可以预先加载具有多层级结构的数据。
比如:
var orders = from o in context.Orders.Include("OrderDetails").Include("Businesses")
where o.CustomerName == "Mac"
select o;
比较两种加载方式
预加载:
• 减少数据访问的延迟,在一次数据库的访问中返回所有的数据。
• 减少与数据库的交互次数
延迟加载:
• 非常宽容,因为只在需要的时候加载数据,不需要预先计划
• 可能会因为数据访问的延迟而降低性能,考虑到每访问父实体的子实体时,就需要访问数据库。
两种加载数据的方式没有什么好坏之分,只是从不同的角度出发适用于不同情况环境。延迟加载更具有灵活性,类似于分治法,每次加载少量数据,分多次加载。但是当主表数据数量过多时,会频繁访问数据库降低性能。预加载只要访问一次数据库就可以拿到全部的数据,放到内存中。但是当数据量很多,或者实体级联关系复杂时要特别注意性能了;实体关系复杂时EF自动生成的sql语句可能会非常复杂,这点也要特别注意。