关于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
作用:在您访问导航属性时,会从数据源自动加载相关实体,若实体尚未在 实体上下文对象中,则您访问的每个导航属性都会导致针对数据源执行一个单独的查询。
示例代码如下:
[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查询路径,查询时仅需对数据库请求一次,即可在单个结果集中返回查询路径所定义的所有实体。
示例代码如下:
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,才会从数据库查询数据并赋值给指定的导航属性,若查询的结果集较多时,可能会出现多次往返查询数据。
示例代码如下:
//这是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(延迟加载)模式,即满足上面第一种关联查询条件时,在执行实体新增的时,需注意:如果直接赋值给导航属性,则当提交到数据库时,会自动关联新增导航属性对应的表记录,不论你是否在实体中有指定导航属性对应的外键属性的值,仍会以关联新增导航属性对应的表记录后更新该外键属性的值,可能表达有点不清楚,请看下面的示例:
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则不赋值,这样在保存时就不会出错了。如果大家知道原因还请告之,非常感谢!
来自:zuowj.cnblogs.com
关于Entity Framework自动关联查询与自动关联更新导航属性对应的实体注意事项说明的更多相关文章
- Entity Framework - 理清关系 - 基于外键关联的单向一对一关系
注:本文针对的是 Entity Framework Code First 场景. 之前写过三篇文章试图理清Entity Framework中的一对一关系(单相思(单向一对一), 两情相悦(双向一对 ...
- Entity Framework入门教程: Entity Framework支持的查询方式
Entity Framework支持的查询方式有三种 LINQ to Entities Entity SQL Native SQL [LINQ to Entities] LINQ(语言集成查询)是从V ...
- Entity Framework常用的查询方式
Entity Framework支持的查询方式有三种 LINQ to Entities Entity SQL Native SQL [LINQ to Entities] LINQ(语言集成查询)是从V ...
- Entity Framework 5.0系列之自动生成Code First代码
在前面的文章中我们提到Entity Framework的"Code First"模式也同样可以基于现有数据库进行开发.今天就让我们一起看一下使用Entity Framework P ...
- 【转】Entity Framework 5.0系列之自动生成Code First代码
在前面的文章中我们提到Entity Framework的“Code First”模式也同样可以基于现有数据库进行开发.今天就让我们一起看一下使用Entity Framework Power Tools ...
- (转)Entity Framework 5.0系列之自动生成Code First代码
原文地址:http://www.cnblogs.com/kenshincui/archive/2013/08/29/3290527.html 在前面的文章中我们提到Entity Framework的“ ...
- 《Entity Framework 6 Recipes》中文翻译系列 (28) ------ 第五章 加载实体和导航属性之测试实体是否加载与显式加载关联实体
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-11 测试实体引用或实体集合是否加载 问题 你想测试关联实体或实体集合是否已经 ...
- Entity Framework做IN查询
开发中遇到的Too high level of nesting for select错误 项目使用了Entity Framework结合Mysql, 遇到了一个非常奇怪的性能问题,一个看起来非常简单的 ...
- Entity Framework Core Like 查询揭秘
在Entity Framework Core 2.0中增加一个很酷的功能:EF.Functions.Like(),最终解析为SQL中的Like语句,以便于在 LINQ 查询中直接调用. 不过Entit ...
随机推荐
- XXX项目总结
前言 昨天晚上睡不着总感觉有些什么东西需要记下来,所以就有了这篇文章.做了好几次的重构是应该有一个总结以备以后查阅,当然有些设计思想是通过自己的总结也有些是吸收别人的思想,同样如果能对你有所帮助那就再 ...
- 人人都是 DBA(VIII)SQL Server 页存储结构
当在 SQL Server 数据库中创建一张表时,会在多张系统基础表中插入所创建表的信息,用于管理该表.通过目录视图 sys.tables, sys.columns, sys.indexes 可以查看 ...
- C#可扩展编程之MEF学习笔记(五):MEF高级进阶
好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...
- js模版引擎handlebars.js实用教程——each嵌套
<!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content="text/ ...
- redis数据结构整理(一)
摘要: 0.redis安装 1.redis的常用数据结构类型 1.1 String 1.2 List 1.3 Set 1.4 Sorted Set 1.5 Hash 2.redis是单进程单 ...
- Thrift架构~thrift中间语言的认识(只有它什么都不是,它才有可能什么都是)
中间语言是我为thrift语言起的名字,呵呵,为什么叫它中间语言呢,其实意思很简单,就是说,它只是一个过程,而不是一个最终的结果,而结果需要这个中间过程的影响,没有中间语言,结果语言也不能产生,在th ...
- gulp学习笔记4
gulp系列学习笔记: 1.gulp学习笔记1 2.gulp学习笔记2 3.gulp学习笔记3 4.gulp学习笔记4 之前的任务都是单个的,比较简单.接下去我们开始引用多个插件,一次性把任务搞定,省 ...
- 快速入门系列--NOSQL--07MongoDB
从我第一次听到Nosql这个概念到如今已经走过4个年头了,但仍然没有具体的去做过相应的实践.最近获得一段学习休息时间,购买了Nosql技术实践一书,正在慢慢的学习.在主流观点中,Nosql大体分为4类 ...
- Topology and Geometry in OpenCascade-Topology
Topology and Geometry in OpenCascade-Topology eryar@163.com 摘要Abstract:本文简要介绍了几何造型中的边界表示法(BRep),并结合程 ...
- WPF自定义控件与样式(12)-缩略图ThumbnailImage /gif动画图/图片列表
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要针对WPF项目 ...