Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 723|回复: 0

如何处理Entity Framework中的DbUpdateConcurrencyException异常

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-8-30 14:11:59 | 显示全部楼层 |阅读模式

    1. Concurrency的作用

    场景

    有个修改用户的页面功能,我们有一条数据User, ID是1的这个User的年龄是20, 性别是female(数据库中的原始数据)

    正确的该User的年龄是25, 性别是male

     

    这个时候A发现User的年龄不对, 就给改成25, 那么在Entity Framework中,我们会这样做。

    var user = dbConext.User.Find(1);
    
    //B用户在这里完成修改了User的性别
    
    user.age = 25;
    
    dbContext.SaveChanges();

     

    但是加入在上面注释处,有个B用户发现性别不对,完成了对用户性别的修改,改成male. 会出现什么结果呢。

    var user = dbConext.User.Find(1);

    当A执行这个代码的时候,获取的性别是female

    user.age = 25;

    当A执行这个代码的时候, 不知道B已经修改了这个记录的性别,这个时候A的user的性别还是female

    dbContext.SaveChanges();

    保存修改的时候,会把female覆盖回去,这样B用户的修改就作废了。

     

    但这不是A的本意,A其实只是想修改年龄而已。

    Entity Framework使用[ConcurrencyCheck] 来解决这种问题, 当标记为[ConcurrencyCheck] 的Entity属性,如果发现在从数据库中取下来和提交的时候不一致,就会出现DbUpdateConcurrencyException异常,避免错误提交。

     

    2. 如何正确处理DbUpdateConcurrencyException异常

    2.1 数据库优先方式

    原理是在出现异常的时候,重新加载数据库中的数据,覆盖Context本地数据

    using (var context = new BloggingContext())
    {
      var blog = context.Blogs.Find(1);
      blog.Name = "The New ADO.NET Blog";  
      bool saveFailed;
      do
      {
        saveFailed = false;
        try
        {
          context.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
          saveFailed = true;
          // Update the values of the entity that failed to save from the store
          ex.Entries.Single().Reload();
        }
      } while (saveFailed);
    }

     

    2.2 客户端优先方式

    以Context保存的客户端数据为主,覆盖数据库中的数据

    using (var context = new BloggingContext())
    {
      var blog = context.Blogs.Find(1);
      blog.Name = "The New ADO.NET Blog";
      bool saveFailed;
      do
      {
        saveFailed = false;
        try
        {
          context.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
          saveFailed = true;
          // Update original values from the database
          var entry = ex.Entries.Single();
          entry.OriginalValues.SetValues(entry.GetDatabaseValues());
        }
      } while (saveFailed);
    } 

     

    3.3 综合方式

    有时候,不是非A即B的关系,我们希望综合数据库中的数据和context中修改的数据,再保存到数据库中

    使用下面的CurrentValues, GetDatabaseValues(), 得到Context数据和数据库数据,重新构建一个正确的Entity,再更新到数据库中

    using (var context = new BloggingContext())
    {
      var blog = context.Blogs.Find(1);
      blog.Name = "The New ADO.NET Blog";
      bool saveFailed;
      do
      {
        saveFailed = false;
        try
        {
          context.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
          saveFailed = true;
          // Get the current entity values and the values in the database
          var entry = ex.Entries.Single();
          var currentValues = entry.CurrentValues;
          var databaseValues = entry.GetDatabaseValues();
          // Choose an initial set of resolved values. In this case we
          // make the default be the values currently in the database.
          var resolvedValues = databaseValues.Clone();
          // Have the user choose what the resolved values should be
          HaveUserResolveConcurrency(currentValues, databaseValues, resolvedValues);
          // Update the original values with the database values and
          // the current values with whatever the user choose.
          entry.OriginalValues.SetValues(databaseValues);
          entry.CurrentValues.SetValues(resolvedValues);
        }
      } while (saveFailed);
    }
    public void HaveUserResolveConcurrency(DbPropertyValues currentValues, DbPropertyValues databaseValues, DbPropertyValues resolvedValues) {   // Show the current, database, and resolved values to the user and have   // them edit the resolved values to get the correct resolution. }

     

    对上面方法的优化

    使用DbPropertyValues总是别扭,使用Enttiy对象就会方便很多,下面就是转换成Entity对象操作的方法

     

    using (var context = new BloggingContext())
    {
      var blog = context.Blogs.Find(1);
      blog.Name = "The New ADO.NET Blog";
      bool saveFailed;
      do
      {
        saveFailed = false;
        try
        {
          context.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
          saveFailed = true;
          // Get the current entity values and the values in the database
          // as instances of the entity type
          var entry = ex.Entries.Single();
          var databaseValues = entry.GetDatabaseValues();
          var databaseValuesAsBlog = (Blog)databaseValues.ToObject();
          // Choose an initial set of resolved values. In this case we
          // make the default be the values currently in the database.
          var resolvedValuesAsBlog = (Blog)databaseValues.ToObject();
          // Have the user choose what the resolved values should be
          HaveUserResolveConcurrency((Blog)entry.Entity,
            databaseValuesAsBlog,
            resolvedValuesAsBlog);
          // Update the original values with the database values and
          // the current values with whatever the user choose.
          entry.OriginalValues.SetValues(databaseValues);
          entry.CurrentValues.SetValues(resolvedValuesAsBlog);
        }
      } while (saveFailed);
    }
    public void HaveUserResolveConcurrency(Blog entity,   Blog databaseValues,   Blog resolvedValues) { // Show the current, database, and resolved values to the user and have // them update the resolved values to get the correct resolution. }

     

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-30 14:01 , Processed in 0.074394 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表