关于Entity Framework自动关联查询与自动关联更新导航属性对应的实体注意事项说明

简介:

一、首先了解下Entity Framework 自动关联查询:

Entity Framework 自动关联查询,有三种方法:Lazy Loading(延迟加载),Eager Loading(预先加载),Explicit Loading(显式加载),其中Lazy Loading和Explicit Loading都是延迟加载。

(注:由于Entity Framework版本的不同,以及采用不同的模式(DB First,Model First,Code First)来构建的Entity,最终导致可能自动关联查询的方法也有所不同,本文中的示例代码均以Entity Framework 6.0,且采用Code First模式来构建的Entity为基础)

一、Lazy Loading(延迟加载):这是默认情况(默认实体上下文对象的属性:Configuration.LazyLoadingEnabled=true,若该属性设为false则无效),若实体类型包含其它实体类型(POCO类)的属性(也可称为导航属性),且同时满足如下条件即可实列延迟加载,

1.该属性的类型必需为public且不能为Sealed;

2.属性标记为Virtual

作用:在您访问导航属性时,会从数据源自动加载相关实体,若实体尚未在 实体上下文对象中,则您访问的每个导航属性都会导致针对数据源执行一个单独的查询。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[Table( "User" ,Schema= "dbo" )]
public  class  User
{
     [Key]
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
     [Display(Name =  "用户ID" )]
     public  int  ID {  get set ; }
 
     [Required]
     [MinLength(6)]
     [MaxLength(15)]
     [Unique( "User" "UserName" )]
     [Display(Name =  "用户名" )]
     public  string  UserName {  get set ; }
 
     [Required]
     [Display(Name =  "密码" )]
     public  string  Password {  get set ; }
 
     [Required]
     [Display(Name =  "用户类型" )]
     public  int  UserTypeID {  get set ; }
 
     [ForeignKey( "UserTypeID" )]
     public  virtual  UserType UserType {  get set ; }  //此属性在查询User时,会自动依据UserTypeID 关联查旬UserType ,并将结果赋值给UserType 属性
}

二、Eager Loading(预先加载):在LazyLoadingEnabled设为false或导航属性没有使用Virtual的情况下,使用IQueryable的扩展方法Include指定预先加载关联的实体。

作用:Include方法中的查询路径指定将哪些相关实体作为初始查询的一部分返回,当在查询语句中定义了Include查询路径,查询时仅需对数据库请求一次,即可在单个结果集中返回查询路径所定义的所有实体。

示例代码如下:

1
2
3
4
5
var  entitiesContext= new  TEMSContext();
entitiesContext.Configuration.LazyLoadingEnabled= false ;
var  users = entitiesContext.Users.Include( "UserType" );
//var users = entitiesContext.Set<User>().Include("UserType");与上面语句相同
Assert.AreNotEqual( null , users.First().UserType);

三、Explicit Loading(显式加载):在LazyLoadingEnabled设为false或导航属性没有使用Virtual的情况下,使用DbEntityEntry.Reference方法来显式加载指定导航属性的单个值,DbEntityEntry.Collection方法来显式加载指定导航属性的值集合,若采用DB First时,可使用ObjectContext.LoadProperty方法来显式加载指定导航属性。

作用:查询时并不会从数据库查询并加载导航属性的值,仅当使用Reference或Collection方法来指定导航属性,并调用Load方法时或调用ObjectContext.LoadProperty,才会从数据库查询数据并赋值给指定的导航属性,若查询的结果集较多时,可能会出现多次往返查询数据。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//这是Code First模式下显式加载数据
var  entitiesContext =  new  TEMSContext();
             entitiesContext.Configuration.LazyLoadingEnabled =  false ;
             var  user = entitiesContext.Users.First();
             var  u = entitiesContext.Entry(user);
             u.Reference(t => t.UserType).Load();
             Assert.AreNotEqual( null , user.UserType);
 
//这是DB First模式下显示式加载数据
var  db =  new  aTestEntities();
             db.ContextOptions.LazyLoadingEnabled =  false ;
             var  comp = db.Companies.First();
             db.LoadProperty(comp, t => t.Departments);
             Assert.AreNotEqual(0, comp.Departments.Count);

二、自动关联更新导航属性对应的实体注意事项说明

若开启了Lazy Loading(延迟加载)模式,即满足上面第一种关联查询条件时,在执行实体新增的时,需注意:如果直接赋值给导航属性,则当提交到数据库时,会自动关联新增导航属性对应的表记录,不论你是否在实体中有指定导航属性对应的外键属性的值,仍会以关联新增导航属性对应的表记录后更新该外键属性的值,可能表达有点不清楚,请看下面的示例:

1
2
3
4
var  entitiesContext =  new  TEMSContext();
User user =  new  User() {UserName= "testuser" ,RealName= "测试账号" ,CompanyID = 1, Company = UserBusiness.CurrentUser.Company };
entitiesContext.Users.Add(user);
entitiesContext.SaveChanges();

 以上代码中,CompanyID为导航属性Company的外键属性,我这里直接将两个属性都赋值了,Company的ID也是1(Company表中存在ID为1的记录),UserBusiness.CurrentUser为我系统当前登录的用户,按理讲,执行新增后,应该只会在User表中新增一条记录,而实际却是先在Company表中新增一条记录(忽略指定的主键,即:ID=1),并将返回的新ID赋值给CompanyID(比如为2),然后再在User表中新增一条记录,最终形成User.CompanyID=2,而不是1,这个问题也是困扰我好几天了,也没有找到根本原因,目前的解决办法是只赋值外键属性CompanyID,而导航属性Company则不赋值,这样在保存时就不会出错了。如果大家知道原因还请告之,非常感谢!

 本文转自 梦在旅途 博客园博客,原文链接:http://www.cnblogs.com/zuowj/p/4514230.html  ,如需转载请自行联系原作者


相关文章
|
SQL 存储 关系型数据库
OceanBase数据库常见问题之部署报错hashtable not init如何解决
OceanBase 是一款由阿里巴巴集团研发的企业级分布式关系型数据库,它具有高可用、高性能、可水平扩展等特点。以下是OceanBase 数据库使用过程中可能遇到的一些常见问题及其解答的汇总,以帮助用户更好地理解和使用这款数据库产品。
|
存储 消息中间件 监控
消息队列和应用工具产品体系-ARMS 服务的产品功能
消息队列和应用工具产品体系-ARMS 服务的产品功能
|
数据采集 运维 前端开发
宜搭产品简介(一)|学习笔记
快速学习宜搭产品简介(一)
866 0
宜搭产品简介(一)|学习笔记
|
SQL Oracle 关系型数据库
SqlSugar
【8月更文挑战第1天】
401 3
|
11月前
|
存储 算法 搜索推荐
【潜意识Java】期末考试可能考的高质量大题及答案解析
Java 期末考试大题整理:设计一个学生信息管理系统,涵盖面向对象编程、集合类、文件操作、异常处理和多线程等知识点。系统功能包括添加、查询、删除、显示所有学生信息、按成绩排序及文件存储。通过本题,考生可以巩固 Java 基础知识并掌握综合应用技能。代码解析详细,适合复习备考。
203 4
|
机器学习/深度学习 监控 搜索推荐
电商平台如何精准抓住你的心?揭秘大数据背后的神秘推荐系统!
【10月更文挑战第12天】在信息爆炸时代,数据驱动决策成为企业优化决策的关键方法。本文以某大型电商平台的商品推荐系统为例,介绍其通过收集用户行为数据,经过预处理、特征工程、模型选择与训练、评估优化及部署监控等步骤,实现个性化商品推荐,提升用户体验和销售额的过程。
617 1
|
人工智能 缓存 机器人
【2024】英伟达吞噬世界!新架构超级GPU问世,AI算力一步提升30倍
英伟达在加州圣荷西的GTC大会上发布了全新的Blackwell GPU,这款拥有2080亿个晶体管的芯片将AI性能推向新高度,是公司对通用计算时代的超越。Blackwell采用多芯片封装设计,通过两颗GPU集成,解决了内存局部性和缓存问题,提供20 petaflops的FP4算力,是上一代产品的5倍。此外,新平台降低了构建和运行大规模AI模型的成本和能耗,使得大型语言模型推理速度提升30倍。黄仁勋表示,Blackwell标志着AI算力在近八年内增长了一千倍,引领了技术边界拓宽的新趋势。
|
编译器 C语言
【C语言】字母转换大小写的三种方法
【C语言】字母转换大小写的三种方法
976 0
|
小程序 前端开发
微信小程序-icon组件
icon 组件,想必大家都应该清楚这个是图标组件吧,在微信小程序当中,为我们提供了一套 icon 图标类型。
549 0
|
安全 调度 PHP
Thinkphp5.0.*之RCE漏洞分析
Thinkphp5.0.*之RCE漏洞分析