一例一个实体对象不能由多个 IEntityChangeTracker 实例引用的解决

本文主要是介绍一例一个实体对象不能由多个 IEntityChangeTracker 实例引用的解决,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前几日在检查日志的时候发现系统偶尔会出现 Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded 的错误,经过查找资料,是因为随着访问量的增多,并发增多造成。解决办法从微软的msdn上找到了想改解决办法。

Entity Framework Optimistic Concurrency Patterns  这里给出了微软这篇文章的链接,我采用的是微软提出的第一种解决办法:Resolving optimistic concurrency exceptions with Reload   其中 update 方法的写法修改成这样:

 public bool Update(T entity){using (var dbContext = new F()){bool saveFailed;do{saveFailed = false;try{//把entity附加到当前dbContextdbContext.Set<T>().Attach(entity);dbContext.Entry<T>(entity).State = EntityState.Modified;return dbContext.SaveChanges() > 0;}catch (DbUpdateConcurrencyException ex){saveFailed = true;// Update the values of the entity that failed to save from the store ex.Entries.Single().Reload();}} while (saveFailed);return false;}}


 当然,添加和删除的相应方法也做了同样的修改,修改后对相应的方法做测试,没有发现什么问题。于是就上线了。因为并发效果在本地没法实现,实际效果需要上线后观察。过了个周末,然后周一来检查执行的效果,Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded 的错误没出现,但是发现大量的 一个实体对象不能由多个 IEntityChangeTracker 实例引用的错误。通过定位,是update方法出现了问题。网上搜索这个错误出现的原因,搜索到的大部分是说由于主从表的关系导致此问题,而且说的都云里雾里,看不懂他们说的意思。但是虽然出错的地方刚好有主从表,但我明白,问题恐怕不是这里。因为这个错误大量出现是在我更改了update方法后才出现的。通过分析我更改的update方法前后的变化,更改前update方法传入的entity实例和update方法SaveChanges 共用的是一个dbcontext, 而更改后,由于使用了 using new 了一个新的 dbcontext,这两个 dbcontext 不一样了,怀疑是这里的问题。而通过把 using 去掉,也真解决了这个问题,不出现 一个实体对象不能由多个 IEntityChangeTracker 实例引用的错误了。但是这样的解决不能令人满意。因为没有理论支撑。由于百度和google都没有找到令人满意的解释,于是把目光投向了 stackoverflow 网站,这个网站还是有许多高手,一些解释感觉很深刻。 通过不停的变换关键词搜索,终于找到了两篇文章解释的比较清楚。我总结了下我这个问题出现的原因是这样的,看这两行代码: 

var examList = es2.Get(m => m.ExamMainGID == examMain.GID && m.QuestionLibraryGID == gid).FirstOrDefault();

es2.Update(examList); 

第一行代码es2.Get方法使用的数据连接是_dbContext, entity framework 每一个查询方法都会自动创建一个 IEntityChangeTracker 的跟踪,这个跟踪是使用的_dbContext连接创建的,他会跟踪exmalList的实例状态变化,比如状态的修改,删除等。而在执行 es2.Update(examList);  这个方法的时候,由于Update方法的实现是 using 了一个新的dbContext: using (var dbContext = new F()), 在这句:dbContext .Set<T>().Attach(entity); 就是把 entity附加到了新的dbContext对象中。按ef的规则,这里是需要创建一个新的 IEntityChangeTracker  跟踪器,就是这行出现了错误。原因就是一个实例的跟踪器只能有一个,在这里这个实例就是examList 。在stackoverflow 网站的这两篇文章中也给出了解决办法。有两种,第一种是公用一个数据连接dbContext,就是我以前的解决办法,不再重新new 一个新的数据连接上下文,而仍然使用es2.Get方法使用的数据连接。另外一种解决办法就属于场合用法了。即把通过 es2.Get方法获取的实例 examList 同_dbContext 剥离开来,然后再把exmaList对象附加到新的 dbContext 对象中。具体的写法是这样的:

//从_dbContext中分离entity
((IObjectContextAdapter)_dbContext).ObjectContext.Detach(entity);
//把entity附加到当前dbContext
dbContext.Set<T>().Attach(entity);dbContext.Entry<T>(entity).State = EntityState.Modified;return _dbContext.SaveChanges() > 0;

这里的((IObjectContextAdapter)_dbContext).ObjectContext.Detach(entity);就是用 Detach 把 entity从 _dbContext上下文数据连接剥离出来。剥离后再附加到新的数据连接中就不会再出现错误。这个方法是不推荐的。如果每次都这样采用剥离的方法,这是增加代码量,共用Context 数据连接才是正确的方法。

这里给出两篇stakoverflow的连接,有兴趣的可以看下:

http://stackoverflow.com/questions/10191734/entity-object-cannot-be-referenced-by-multiple-instances-of-ientitychangetracker

http://stackoverflow.com/questions/12112360/c-sharp-entity-framework-ientitychangetracker-issue

这篇关于一例一个实体对象不能由多个 IEntityChangeTracker 实例引用的解决的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/768179

相关文章

Springboot项目启动失败提示找不到dao类的解决

《Springboot项目启动失败提示找不到dao类的解决》SpringBoot启动失败,因ProductServiceImpl未正确注入ProductDao,原因:Dao未注册为Bean,解决:在启... 目录错误描述原因解决方法总结***************************APPLICA编

解决pandas无法读取csv文件数据的问题

《解决pandas无法读取csv文件数据的问题》本文讲述作者用Pandas读取CSV文件时因参数设置不当导致数据错位,通过调整delimiter和on_bad_lines参数最终解决问题,并强调正确参... 目录一、前言二、问题复现1. 问题2. 通过 on_bad_lines=‘warn’ 跳过异常数据3

解决RocketMQ的幂等性问题

《解决RocketMQ的幂等性问题》重复消费因调用链路长、消息发送超时或消费者故障导致,通过生产者消息查询、Redis缓存及消费者唯一主键可以确保幂等性,避免重复处理,本文主要介绍了解决RocketM... 目录造成重复消费的原因解决方法生产者端消费者端代码实现造成重复消费的原因当系统的调用链路比较长的时

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

kkFileView启动报错:报错2003端口占用的问题及解决

《kkFileView启动报错:报错2003端口占用的问题及解决》kkFileView启动报错因office组件2003端口未关闭,解决:查杀占用端口的进程,终止Java进程,使用shutdown.s... 目录原因解决总结kkFileViewjavascript启动报错启动office组件失败,请检查of

SQL Server安装时候没有中文选项的解决方法

《SQLServer安装时候没有中文选项的解决方法》用户安装SQLServer时界面全英文,无中文选项,通过修改安装设置中的国家或地区为中文中国,重启安装程序后界面恢复中文,解决了问题,对SQLSe... 你是不是在安装SQL Server时候发现安装界面和别人不同,并且无论如何都没有中文选项?这个问题也

MyBatis-Plus 自动赋值实体字段最佳实践指南

《MyBatis-Plus自动赋值实体字段最佳实践指南》MyBatis-Plus通过@TableField注解与填充策略,实现时间戳、用户信息、逻辑删除等字段的自动填充,减少手动赋值,提升开发效率与... 目录1. MyBATis-Plus 自动赋值概述1.1 适用场景1.2 自动填充的原理1.3 填充策略

MySQL多实例管理如何在一台主机上运行多个mysql

《MySQL多实例管理如何在一台主机上运行多个mysql》文章详解了在Linux主机上通过二进制方式安装MySQL多实例的步骤,涵盖端口配置、数据目录准备、初始化与启动流程,以及排错方法,适用于构建读... 目录一、什么是mysql多实例二、二进制方式安装MySQL1.获取二进制代码包2.安装基础依赖3.清