EF异常探究(An entity object cannot be referenced by multiple instances of IEntityChangeTracker.)
今天在改造以前旧项目时出现了一项BUG,是由于以前不规范的EF写法所导致。异常信息如下:
"An entity object cannot be referenced by multiple instances of IEntityChangeTracker(一个实体对象不能由多个 IEntityChangeTracker 实例引用)"
这个问题其实很容易定位,是因为在程序中
使用了不同的DbContext来追踪同一个实体。
以下的Demo代码可以轻松地引发该异常:
using (var dbContext = new ADbContext())
{var aa = dbContext.ClassA.Where(p => p.Id == ).FirstOrDefault();
dbContext.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
using (var db2 = new ADbContext())
{
db2.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
dbContext.SaveChanges();
}
dbContext.SaveChanges();
}
注意ClassA一定要具有 导航属性 ,如下:
public class ClassA {
public int Id { get; set; }
public string guid { get; set; }
public int? child_id { get; set; } [ForeignKey("child_id")]
public virtual ClassB child { get; set; }
}
多数场景下,一个设计好的系统中都会使用Uow(工作单元)来保证每一次请求使用同一个DbContext(也会有一些系统会需要MSDTC,不在讨论范围内),任意新建DbContext不但容易引发异常,还有可能因为释放不及时而导致内存问题。
要解决上面的这个异常很简单——使用同一个DbContext就行了。
可问题是:
为什么这个项目在以前的运行过程中没有引发错误?
探究
还是上面那个项目,我们把导航属性的 Virtual 去掉,如下:
public class ClassA {
public int Id { get; set; }
public string guid { get; set; }
public int? child_id { get; set; } [ForeignKey("child_id")]
public ClassB child { get; set; }
}
运行项目,你会发现异常不见了。
究竟是什么原因?
对EF稍微了解的同学都知道,EF的导航属性默认是开启延迟加载的。
不了解的同学请搜索关键字补充一下关于EF延迟加载的基础知识,英语能力不错的同学请浏览官方文档( 关联与导航属性, 加载关联实体)
去掉了virtual后,关闭了该导航属性的延迟加载功能,然后异常消失了。
是因为延迟加载导致的这个异常吗?
延迟加载又和IEntityChangeTracker有什么关系呢?
原因
顾名思义,其实 IEntityChangeTracker 就是用来追踪实体信息的,但令人不解的是,为什么关闭延迟加载之后,就算实体同时被两个DbContext追踪也不会报错。
来考虑一下EF的延迟加载是如何实现的,
EF使用了与Castle类似的动态代理技术,同时也存在着相同的缺陷(无法拦截没有被标识为virtual的成员)。
由于没看过EF的源码,官方文档也没有详细的说明,所以我只能推测,IEntityChangeTracker其实发挥类似拦截器的功能,
调用DbContext时,由EF产生实体的动态代理,在访问导航属性时,拦截请求访问数据库并填充导航属性。
而动态代理在产生之后,就无法在Attach到其他的DbContext中。
基于这个推测,我们可以使用一下的代码进行测试,关闭DbContext动态代理。
using (var dbContext = new ADbContext())
{
dbContext.Configuration.ProxyCreationEnabled = false;
var aa = dbContext.ClassA.Where(p => p.Id == ).FirstOrDefault();
dbContext.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
using (var db2 = new ADbContext())
{
db2.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
dbContext.SaveChanges();
}
dbContext.SaveChanges();
}
结果通过。
为了证明该异常其实跟延迟加载没有关系,我们可以开启动态代理,然后关闭延迟加载。
using (var dbContext = new ADbContext())
{
dbContext.Configuration.ProxyCreationEnabled = true;
dbContext.Configuration.LazyLoadingEnabled = false;
var aa = dbContext.ClassA.Where(p => p.Id == ).FirstOrDefault();
dbContext.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
using (var db2 = new ADbContext())
{
db2.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
dbContext.SaveChanges();
}
dbContext.SaveChanges();
}
异常依旧发生。
证明引发该异常的并不是延迟加载功能,而在于EF动态代理的对象只能由一个DbContext追踪。
还有一点值得一提的是:
如果一个实体没有导航属性的话,EF也不会生成它的动态代理。
EF异常探究(An entity object cannot be referenced by multiple instances of IEntityChangeTracker.)的更多相关文章
- EntityFramework 异常 -- An entity object cannot be referenced by multiple instances of IEntityChangeTracker
问题 在调用 DbSet 的 Attach() 方法时(与将 Entity 设置为 EntityState.Unchanged 状态等价)报告以下错误: An entity ob ...
- An entity object cannot be referenced by multiple instances of IEntityChangeTracker 的解决方案
使用EF对建立了关系的表新增记录时出现: An entity object cannot be referenced by multiple instances of IEntityChangeTra ...
- An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
如果你和我一样遇到了这个问题,那么你就要检查你要操作的Model对象查询,更新操作的数据库上下文也就是DBContext是否一致.如果不一致也就是说你用AContext去查如AContext.SET& ...
- EBS OAF开发中的Java 实体对象(Entity Object)验证功能补充
EBS OAF开发中的Java 实体对象(Entity Object)验证功能补充 (版权声明,本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处:否则请与本人联系,违者必究) EO理论上 ...
- 记录一个EF连接查询的异常:the entity or complex type 'x' cannot be constructed in a linq to entities query
问题解决连接:https://stackoverflow.com/questions/5325797/the-entity-cannot-be-constructed-in-a-linq-to-ent ...
- EF中System.Data.Entity.Internal.AppConfig的类型初始值设定项引发异常
使用Entity的时候遇到的一个错 问题出在项目的App.config中 解决: 1.configSections要写在最顶端 2. 当中的incariantName会变成incariantNodeN ...
- APS.NET MVC + EF (02)---ADO.NET Entity FrameWork
2.1 Entity Framework简介 Ado.net Entity Framework 是Microsoft推出的ORM框架. 2.1.1 什么是ORM 对象关系映射(Object Relat ...
- 怎么搭建EF的环境?(Entity Framework)
1.EF是什么? EF是.net封装的一个用于数据库交互的实体层框架,它的全称是Entity Framework. 2.EF搭建: 新建之后,我们就可以看到里面的内容: 我们可以分别看一下它里面有些什 ...
- ASP.NET Core ActionFilter引发的一个EF异常
最近在使用ASP.NET Core的时候出现了一个奇怪的问题.在一个Controller上使用了一个ActionFilter之后经常出现EF报错. InvalidOperationException: ...
随机推荐
- 201521123096《Java程序设计》第十三周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...
- Java程序设计——学生基本信息管理系统
1.团队课程设计博客链接 http://www.cnblogs.com/handsome321/p/7067121.html 2.个人负责模块说明 本组课题:学生信息管理系统 本人任务:插入.删除学生 ...
- PowerDesigner连接MySQL和逆向工程图
0.写在前面的话 最近想梳理公司项目的表间关系,从项目后台管理系统的操作入手,以及代码的hibernate注解入手,都不算特别尽人意,于是最后还是鼓捣了一下PowerDesigner的逆向工程图,这样 ...
- jquery-post get 同步问题
解决方法1: 在全局设置: $.ajaxSetup({ async : false }); 然后再使用get.post请求 $.get("register/RegisterState&quo ...
- cocos2dx 播放gif
起因 或许有人会说,cocos2dx中直接帧动画就行了用什么GIF. 起因是为游戏内部要用到第三方平台的头像,而第三方平台的头像大多都是用到Gif,所以才会有了这个需求 过程 查了各种文档都没找到.但 ...
- Maven(五)之Maven配置阿里云镜像飞快下jar包
用过Maven的人都知道Maven对于依赖的管理让我们程序员从此远离了自己去在项目中把需要的jar包导入到项目中,但是因为中央仓库是在国外的,所以在我们从中央仓库下载依赖的时候, 我们发现下载速度真的 ...
- AngularJS的运用
前 言 JRedu AngularJS[1] 诞生于2009年,由Misko Hevery 等人创建,后为Google所收购.是一款优秀的前端JS框架,已经被用于Google的多款产品当中.A ...
- SqlHelper工具类
public class SqlHlper { public static readonly string constr = ConfigurationManager.ConnectionString ...
- SpringMVC上传压缩文件,解压文件,并检测上传文件中是否有index.html
SpringMVC上传压缩文件,解压文件,并检测上传文件中是否有index.html 说明: 1.环境:SpringMVC+Spring+Tomcat7+JDK1.7 2.支持 zip和rar格式的压 ...
- 【转】Python正则表达式指南
1. 正则表达式基础 1.1. 简单介绍 正则表达式并不是Python的一部分.正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十 ...