Entity Framework with MySQL Provider 更新行数为0的Bug

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 本文将很容易解决的问题搞复杂了,多数情况下将MySql连接字符串中的Use Affected Rows参数设置为true即可。 2012-06-17 作者注。   在使用MySQL数据库来做为Entity Framework的Provider时,有时会遇到如下问题: 存储区更新、插入或删除语句影响到了意外的行数(0)。

本文将很容易解决的问题搞复杂了,多数情况下将MySql连接字符串中的Use Affected Rows参数设置为true即可。

2012-06-17 作者注。

 

在使用MySQL数据库来做为Entity Framework的Provider时,有时会遇到如下问题:

存储区更新、插入或删除语句影响到了意外的行数(0)。实体在加载后可能被修改或删除。刷新 ObjectStateManager 项。

问题产生的场景可能为:

通常会遇到这样的问题,我们打开编辑界面,然后不更改任何内容,然后点保存,基本流程为

   1: var detail=db.Table.FirstOrDefault(c=>c.id==1);
   2: detail.Content=model.Content;
   3: db.SaveChanges();

因为我们没有更改任何内容,所以更改前与更改后的内容是一致的,这时会报出以上错误

其原因是因为MySQL与SQLServer的处理机制不同,如果更新内容与数据库的一致,SQLServer仍然会返回受影响行数为1,但是MySQL则会认为受影响行数为0。

而Entity Framework应该是默认以SQLServer的为准,所以认为如果更新了,但是返回受影响条数为0,则认为是更新不正确

我们处理这个问题有很多方法 ,最笨的应该是在赋值前进行判断,detail.Content是否与model.Content相等,如果相等就不进行赋值。

不过因为EntityFramework是在我们对属性赋值时更新了此属性的State使之标识为Modified或Deleted等 状态,所以我们是可以有更方便的方法来控制这些更新的。

我们可以使用EntityFramework的Context中的SavingChanges这个事件在SaveChanges之前做一些处理:

其基本原理为

if(当前实体已经修改 && 所有属性更改后的值与更改前的值相同){

使之不更新

}

我具体代码实现如下

   1: public class EntityFrameworkFix
   2:     {
   3:         public static void SavingChanges(object sender, EventArgs e)
   4:         {
   5:             var context = sender as ObjectContext;
   6:             if (context == null) return;
   7:             var updatedEntites = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
   8:  
   9:             foreach (var ose in updatedEntites)
  10:             {
  11:                 var props = ose.GetModifiedProperties().ToList();
  12:                 int modifyCount = 0;
  13:                 int propCount = props.Count();
  14:                 for (int i = 0; i < propCount; i++)
  15:                 {
  16:                     var prop = props[i];
  17:                     var index = ose.OriginalValues.GetOrdinal(prop);
  18:                     if (ose.OriginalValues.GetValue(index).Equals(ose.CurrentValues.GetValue(index)))
  19:                     {
  20:                         modifyCount++;
  21:                     }
  22:                 }
  23:                 if (modifyCount == propCount)
  24:                 {
  25:                     context.Refresh(RefreshMode.StoreWins, ose.Entity);
  26:                 }
  27:             }
  28:         }
  29:     }

然后我们在我们声明Context时添加如下事件

   1: db.SavingChanges += EntityFrameworkFix.SavingChanges;

这样就可以不执行那些赋值了,但值没有变化的Update。

另外,前些天EntityFramework4.1也发布了,但是因为EntityFramework4.1中不再支持SavingChanges所以我们要使用其它方法 来支持,我们可以在DbContext中override ValidateEntity方法来实现这一过程

   1: public partial class MyEntities : DbContext
   2: {
   3:     protected override System.Data.Entity.Validation.DbEntityValidationResult ValidateEntity(System.Data.Entity.Infrastructure.DbEntityEntry entityEntry, System.Collections.Generic.IDictionary<object, object> items)
   4:     {
   5:         int wrongCount = 0;
   6:         int allCount = 0;
   7:         if(entityEntry.State== System.Data.EntityState.Modified)
   8:         {
   9:             foreach(var name in entityEntry.OriginalValues.PropertyNames)
  10:             {
  11:                 var prop = entityEntry.Property(name);
  12:                 if (prop.IsModified)
  13:                 {
  14:                     allCount++;
  15:                     if (prop.OriginalValue.Equals(prop.CurrentValue))
  16:                         wrongCount++;
  17:                 }
  18:  
  19:             }
  20:             if (wrongCount == allCount)
  21:                 entityEntry.State = System.Data.EntityState.Unchanged;
  22:         }
  23:         return base.ValidateEntity(entityEntry, items);
  24:     }
  25: }
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
1
分享
相关文章
(十八)MySQL排查篇:该如何定位并解决线上突发的Bug与疑难杂症?
前面《MySQL优化篇》、《SQL优化篇》两章中,聊到了关于数据库性能优化的话题,而本文则再来聊一聊关于MySQL线上排查方面的话题。线上排查、性能优化等内容是面试过程中的“常客”,而对于线上遇到的“疑难杂症”,需要通过理性的思维去分析问题、排查问题、定位问题,最后再着手解决问题,同时,如果解决掉所遇到的问题或瓶颈后,也可以在能力范围之内尝试最优解以及适当考虑拓展性。
459 3
MySQL——查看当前数据库中所有库中表的行数
MySQL——查看当前数据库中所有库中表的行数
45 0
MySQL 中单表数据的最大行数应该控制在多少?
MySQL 中单表数据的最大行数应该控制在多少?
2443 1
MySQL 中单表数据的最大行数应该控制在多少?
【Bug解决】Thinkphp5 PDO::__construct(): MySQL server has gone away解决办法
【Bug解决】Thinkphp5 PDO::__construct(): MySQL server has gone away解决办法
198 0
故障案例:MySQL唯一索引有重复值,官方却说This is not a bug
故障案例:MySQL唯一索引有重复值,官方却说This is not a bug
295 0
这次被坑惨了,MySQL的隐式转换导致了一个线上BUG
某一天,开发问我,为什么针对一个查询会有两条记录,且其中一条记录并不符合条件select * from tablea where xxno = 170325171202362928;xxno为 170325171202362928 和 170325171202362930的都出现在结果中。 一个等值查询为什么会有另外一个不同值的记录查询出来呢? 我们一起来看看究竟!