Entity Framework允许控制对象之间的关系,在使用EF的过程中,很多时候我们会进行查询的操作,当我们进行查询的时候,哪些数据会被加载到内存中呢?所有的数据都需要吗?在一些场合可能有意义,例如:当查询的实体仅仅拥有一个相关的子实体时可以加载所有的数据到内存中。但是,在多数情况下,你可能并不需要加载全部的数据, 而是只要加载一部分的数据即可。

默认情况下,EF仅仅加载查询中涉及到的实体,但是它支持两种特性来帮助你控制加载:

1、贪婪加载

2、延迟加载

下面以客户类型、客户和客户邮件三个实体之间的关系来讲解两种加载方式。

从上图可以看出三个实体类之间的关系:

客户类型和客户是一对多的关系:一个客户类型可以有多个客户。
客户和客户邮件是一对一的关系:一个客户只有一个邮箱地址。(假设只有一个邮箱地址)

一、延迟加载(Lazy Loading)

延迟加载:即在需要或者使用的时候才会加载数据。默认情况下,EF使用延迟加载的方式来加载数据。延迟加载是这样一种过程:直到LINQ查询的结果被枚举时,该查询涉及到的相关实体才会从数据库加载。如果加载的实体包含了其他实体的导航属性,那么直到用户访问该导航属性时,这些相关的实体才会被加载。

使用延迟加载必须满足两个条件:
1、实体类是由Public修饰符修饰的,不能是封闭类。
2、导航属性标记为Virtual。

1、定义实体类

CustomerType实体类定义如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace LazyLoding.Model
{
public class CustomerType
{
public int CustomerTypeId { get; set; }
public string Description { get; set; } // 导航属性使用virtual关键字修饰,用于延迟加载
public virtual ICollection<Customer> Customers { get; set; }
}
}

Customer实体类定义如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace LazyLoding.Model
{
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; } // 导航属性使用virtual关键字修饰,用于延迟加载
public virtual CustomerType CustomerType { get; set; }
// 导航属性使用virtual关键字修饰,用于延迟加载
public virtual CustomerEmail CustomerEmail { get; set; }
}
}

CustomerEmail实体类定义如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace LazyLoding.Model
{
public class CustomerEmail
{
public int CustomerEmailId { get; set; }
public string Email { get; set; }
// 导航属性使用virtual关键字修饰,用于延迟加载
public virtual Customer Customer { get; set; }
}
}

2、定义数据上下文类,并配置实体关系

 using LazyLoding.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace LazyLoding.EF
{
public class Context :DbContext
{
public Context()
: base("name=AppConnection")
{ } #region 将领域实体添加到DbSet中
public DbSet<CustomerType> CustomerTypes { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<CustomerEmail> CustomerEmails { get; set; }
#endregion protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// 设置表名和主键
modelBuilder.Entity<CustomerType>().ToTable("CustomerType").HasKey(p => p.CustomerTypeId);
modelBuilder.Entity<Customer>().ToTable("Customer").HasKey(p => p.CustomerId);
modelBuilder.Entity<CustomerEmail>().ToTable("CustomerEmail").HasKey(p => p.CustomerEmailId); // 设置实体关系
/*
配置一对多关系
HasMany:表示一个CustomerType里面包含多个Customers
WithRequired:表示必选,CustomerType不能为空
MapKey:定义实体之间的外键
*/
modelBuilder.Entity<CustomerType>().HasMany(p => p.Customers).WithRequired(t => t.CustomerType)
.Map(m =>
{
m.MapKey("CustomerTypeId");
}); /*
配置一对一的关系
HasRequired:表示前者必选包含后者,前者可以独立存在,后者不可独立存在
WithRequiredPrincipal:指明实体的主要 这里表示指定Customer表是主表可以独立存在
MapKey:定义实体之间的外键
*/
modelBuilder.Entity<Customer>().HasRequired(p => p.CustomerEmail).WithRequiredPrincipal(t => t.Customer)
.Map(m =>
{
m.MapKey("CustomerId");
});
base.OnModelCreating(modelBuilder);
}
}
}

3、使用数据迁移生成数据库,并重写Configuration类的Seed()方法填充种子数据

Configuration类定义如下:

 namespace LazyLoding.Migrations
{
using LazyLoding.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq; internal sealed class Configuration : DbMigrationsConfiguration<LazyLoding.EF.Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
} protected override void Seed(LazyLoding.EF.Context context)
{
// This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. // 初始化种子数据
context.CustomerTypes.AddOrUpdate(
new CustomerType()
{
Description = "零售",
Customers = new List<Customer>()
{
new Customer(){Name="小乔", CustomerEmail=new CustomerEmail(){ Email="qiao@qq.com"}},
new Customer(){Name="周瑜",CustomerEmail=new CustomerEmail(){Email="yu@126.com"}}
}
},
new CustomerType()
{
Description = "电商",
Customers = new List<Customer>()
{
new Customer(){Name="张飞", CustomerEmail=new CustomerEmail(){Email="zf@qq.com"}},
new Customer(){Name="刘备",CustomerEmail=new CustomerEmail(){Email="lb@163.com"}}
}
}
);
}
}
}

4、查看生成的数据库

5、查看Main方法,并打开SQL Server Profiler监视器监视数据库

// 还没有查询数据库
var customerType = dbContext.CustomerTypes;

继续执行

查看监视器:

发现这时候产生了查询的SQL语句。

这就是EF的延迟加载技术,只有在数据真正用到的时候才会去数据库中查询。

使用Code First时,延迟加载依赖于导航属性的本质。如果导航属性是virtual修饰的,那么延迟加载就开启了,如果要关闭延迟加载,不要给导航属性加virtual关键字就可以了。

注意:如果想要为所有的实体关闭延迟加载,那么可以在Context的构造函数中配置关闭属性即可,代码如下:

public Context() : base("name=AppConnection")
{
// 配置关闭延迟加载
this.Configuration.LazyLoadingEnabled = false;
}

2、贪婪加载(Eager Load)

贪婪加载:顾名思义就是一次性把所有数据都加载出来。贪婪加载是这样一种过程:当我们要加载查询中的主要实体时,同时也加载与之相关的所有实体。要实现贪婪加载,我们要使用Include()方法。

下面我们看一下如何在加载Customer数据的时候,同时也加载所有的CustomerType数据(操作此功能时暂时先关闭延迟加载以免影响)。

//贪婪加载,以下两种方式都可以
// 在使用Lambda表达式指明要加载的导航实体时,要引用命名空间:System.Data.Entity
var customers = dbContext.Customers.Include(p => p.CustomerType).Include(p => p.CustomerEmail).ToList();
//方式2
var query = dbContext.Customers.Include("CustomerType").Include("CustomerEmails");

总结:

贪婪加载:

1、减少数据访问的延迟,在一次数据库的访问中返回所有的数据。

2、一次性加载所有的数据到内存中,可能导致部分数据实际用不到,从而导致读取数据的速度变慢,效率变低。

延迟加载:

1、只在需要读取关联数据的时候才进行加载。每一条数据都会访问一次数据库,导致数据库的压力加大。

2、可能因为数据访问的延迟而降低性能,因为循环中,每一条数据都会访问一次数据库,导致数据库的压力增大。

如何选择使用哪种查询机制:

1、如果是在foreach循环中加载数据,那么使用延迟加载会比较好,因为不需要一次性将所有数据都读取出来,这样虽然可能会造成多次查询数据库,但基本上在可以接受的范围之内。

2、如果在开发时就可以预见需要一次性加载所有的数据,包含关联表的所有数据,那么使用贪婪加载是比较好的选择,但是此种方式会导致效率问题,尤其是在数据量大的情况下。

代码下载地址:https://pan.baidu.com/s/1kVSpH1l

Entity Framework应用:Loading Entities的更多相关文章

  1. Entity Framework 6 vs NHibernate 4

    This article is dedicated to discussing the latest releases of the NHibernate and Entity Framework. ...

  2. Data Developer Center > Learn > Entity Framework > Get Started > Loading Related Entities

    Data Developer Center > Learn > Entity Framework > Get Started > Loading Related Entitie ...

  3. Entity Framework Tutorial Basics(37):Lazy Loading

    Lazy Loading: One of the important functions of Entity Framework is lazy loading. Lazy loading means ...

  4. Entity Framework Tutorial Basics(36):Eager Loading

    Eager Loading: Eager loading is the process whereby a query for one type of entity also loads relate ...

  5. 【转】Entity Framework技术系列之7:LINQ to Entities

    前言 LINQ(Language Integrated Query,语言集成查询)是一组用于C#和VB.NET语言的扩展,它允许编写C#或者VB.NET代码,以与查询数据库相同的方式操作内存数据. L ...

  6. ORM Entities vs. Domain Entities under Entity Framework 6.0

    I stumbled upon the following two articles First and Second in which the author states in summary th ...

  7. Code First Entity Framework 6化被动为主动之explicit loading模式实战分析( 附源码)

    在使用Entity Framework加载关联实体时,可以有三种方式: 1.懒加载(lazy Loading); 2.贪婪加载(eager loading); 3.显示加载(explicit load ...

  8. Entity Framework加载相关实体——延迟加载Lazy Loading、贪婪加载Eager Loading、显示加载Explicit Loading

    Entity Framework提供了三种加载相关实体的方法:Lazy Loading,Eager Loading和Explicit Loading.首先我们先来看一下MSDN对三种加载实体方法的定义 ...

  9. Entity Framework Tutorial Basics(22):Disconnected Entities

    Disconnected Entities: Before we see how to perform CRUD operation on disconnected entity graph, let ...

随机推荐

  1. golang(5)使用beego 开发 api server 和前端同学拆分开发,使用swagger

    1,beego api Swagger 是一个规范和完整的框架,用于生成.描写叙述.调用和可视化 RESTful 风格的 Web 服务.整体目标是使client和文件系统作为服务器以相同的速度来更新. ...

  2. DevExpress控件之"XtraForm——窗体"

    1.AutoScaleMode:确定当屏幕分辨率或字体更改时窗体或控件将如何缩放. Dpi:根据显示分辨率控制缩放.常用分辨率为96和120Dpi: Font:根据类使用的字体(通常为系统字体)的维度 ...

  3. mysql 慢查询日志,灾难日志恢复,错误日志

    灾难日志 记录了所有的DDL(Create.Drop和Alter)和DML(insert.update.delete_的语句,但不包括查询的语句 打开mysql.ini 找到Binary Loggin ...

  4. ps换衣服

    1.抠衣服->给衣服新建图层(ctrl+j)->给图层去色,让衣服边黑白色.2.剪贴蒙版(上图:大花布,下形:衣服).作用:大花布替换成衣服3.大花布图层->叠加图层样式或其它图层样 ...

  5. IO模型-java版

    描述IO,我们需要从两个层面: 编程语言 实现原理 底层基础 从编程语言层面 BIO | NIO | AIO 以Java的角度,理解,linux c里也有AIO的概念(库),本文只从Java角度入手. ...

  6. mybatis 一二事(2) - 动态代理

    db.properties 单独提取出来的数据库配置,方便以后维护管理 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhos ...

  7. iOS改变UINavigationBar导航条标题颜色和字体

    转自:http://www.2cto.com/kf/201311/260409.html iOS 5 以后 UINavigationController 可以 改变UINavigationBar导航条 ...

  8. mysql插入中文时候编码问题

    mysql插入中的时候要设置 set character_client_set = utf-8

  9. Swift语言 简明基础 代码演示样例

    开发环境: Mac.Xcode6.0 下面内容均可创建ios common line项目来測试 1.Hello World演示样例 使用xcode创建新的common line项目,查看主文件main ...

  10. hdoj 2717 Catch That Cow

    Problem Description Farmer John has been informed of the location of a fugitive cow and wants to cat ...