EF学习和使用(五)Lazy Loading and Eager Loading

想熟练正确的使用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的查询。

EF学习和使用(五)Lazy Loading and Eager Loading_第1张图片


如果将数据库上下文的属性设置为 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

}

EF学习和使用(五)Lazy Loading and Eager Loading_第2张图片


如果你查看SQl Server Profiler中的跟踪信息,你会发现只有一次数据交互过程,即程序只通过一次查询便获取到了所有需要的数据。它也可以减少程序与数据库的交互次数。不过仍然有缺点,那就是如果数据量较大,一次性将所有数据载入内存往往并不是最明智的选择。.Include(Entity)方法允许级联使用,你可以预先加载具有多层级结构的数据。

比如:

var orders = from o in context.Orders.Include("OrderDetails").Include("Businesses") 
where o.CustomerName == "Mac" 
select o; 

比较两种加载方式

预加载:

• 减少数据访问的延迟,在一次数据库的访问中返回所有的数据。
• 减少与数据库的交互次数

延迟加载:

• 非常宽容,因为只在需要的时候加载数据,不需要预先计划
• 可能会因为数据访问的延迟而降低性能,考虑到每访问父实体的子实体时,就需要访问数据库。

两种加载数据的方式没有什么好坏之分,只是从不同的角度出发适用于不同情况环境。延迟加载更具有灵活性,类似于分治法,每次加载少量数据,分多次加载。但是当主表数据数量过多时,会频繁访问数据库降低性能。预加载只要访问一次数据库就可以拿到全部的数据,放到内存中。但是当数据量很多,或者实体级联关系复杂时要特别注意性能了;实体关系复杂时EF自动生成的sql语句可能会非常复杂,这点也要特别注意。

你可能感兴趣的:(延迟加载,ef,预加载)