zoukankan      html  css  js  c++  java
  • Entity Framework with MySQL Provider 更新行数为0的Bug

    本文将很容易解决的问题搞复杂了,多数情况下将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: }
  • 相关阅读:
    Laravel 项目架构 弹性、可维护性
    QT信号槽详解
    linux常用命令
    程序莫名其妙的崩溃,加断点刚进入函数就崩溃,断点不往下走,读取图片数据到程序并保存到一个HBITMAP 中
    C++ 实现sqilte创建数据库插入、更新、查询、删除
    dump、libeay32.dll、gsoap、webserver多线程调用gsoap产生崩溃
    bat自动打包压缩实现
    linux 文件名称前后缀操作函数----取目录函数dir、取文件名称函数notdir、取后缀函数suffix、取前缀basename、加后缀函数addsuffix、加前缀addprefix、连接函数join
    linux makefile字符串操作函数 替换subst、模式替换patsubst、去首尾空格strip、查找字符串findstring、过滤filter、反过滤filter-out、排序函数sort、取单词word、取单词串wordlist、个数统计words
    makefile编写--引用
  • 原文地址:https://www.cnblogs.com/chsword/p/ef_mysql_update.html
Copyright © 2011-2022 走看看