1. Concurrency的作用

场景

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

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

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

var user = dbConext.User.Find();

//B用户在这里完成修改了User的性别

user.age = ;

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();
  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();
  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();
  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();
  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.
}

 

 
 

如何处理Entity Framework中的DbUpdateConcurrencyException异常的更多相关文章

  1. 如何处理Entity Framework / Entity Framework Core中的DbUpdateConcurrencyException异常(转载)

    1. Concurrency的作用 场景有个修改用户的页面功能,我们有一条数据User, ID是1的这个User的年龄是20, 性别是female(数据库中的原始数据)正确的该User的年龄是25, ...

  2. 在Entity Framework中使用事务

    继续为想使用Entity Framework的朋友在前面探路,分享的东西虽然技术含量不高,但都是经过实践检验的. 在Entity Framework中使用事务很简单,将操作放在TransactionS ...

  3. Entity Framework 教程——Entity Framework中的实体类型

    Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...

  4. 关于Entity Framework中的Attached报错相关解决方案的总结

    关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...

  5. 关于Entity Framework中的Attached报错的完美解决方案终极版

    之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...

  6. [转]在Entity Framework中使用LINQ语句分页

    本文转自:http://diaosbook.com/Post/2012/9/21/linq-paging-in-entity-framework 我们知道,内存分页效率很低.并且,如果是WebForm ...

  7. Entity Framework中的多个库操作批量提交、事务处理

    在Entity Framework 中使用SaveChanges()是很频繁的,单次修改或删除数据后调用SaveChanges()返回影响记录数. 要使用批量修改或者批量删除数据,就需要SaveCha ...

  8. LinqToSql和ASP.NET Entity FrameWork 中使用事务

    ASP.NET Entity FrameWork中: int flag = -1; if (this.URPmanagementEntities1.Connection.State != System ...

  9. Lazy<T>在Entity Framework中的性能优化实践

    Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...

随机推荐

  1. c#使用QQ邮箱的SSL收发邮件

    c#使用SMTP.QQ.COM的SSL验证时,收发邮件,请勿设置端口,代码如下: (1)虽然SSL端口是465,但是,在代码里,不能直接设置端口,很奇怪?挺奇怪,好吧腾讯SSL好像用的是587端口!! ...

  2. HttpContext.Current.Session 和 Session 的区别

    Session(会话)通常指一个动作从开始到结束不间断的一个动作. 例如“打电话”,通常是“1.拿起电话--2.拨对方号码--3.对方截图--4.挂机”.这四个步骤从完成到结束组成了一个基本的Sess ...

  3. 洛谷 P1347 排序

    题目描述 一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列A,B,C,D 表示A<B,B<C,C<D.在这道题中,我们将给你一系列形如A<B ...

  4. 诺基亚S40手机联系人导入安卓手机

    电话号码较少的话比较简单,拷贝到SIM卡中通过SIM卡中转,只是一般SIM卡只能存储200个左右,联系人比较多的情况就麻烦一点,今天帮导师把诺基亚5220中的800个电话转到三星S4中,综合下来还是使 ...

  5. QT入门系列(3):控制台输出QString

    方式一:使用qDebug()输出 QString str("liyifeng");qDebug() << str;12输出结果:"liyifeng" ...

  6. c++字符串split 函数实现

    - 经常遇到字符串分割问题,但是相对于c++而言实现比较麻烦,直接遍历一遍也很冗余 - 另外也适用于,在字符串中找到某个字符的所有位置 //函数功能:将输入字符串s,以字符串c(;)进行拆分,拆分结果 ...

  7. 记录Activity启动时间 ActivityLifecycleCallbacks

    ActivityStackManager 定义一个集合(Stack)保存所有还未销毁的 Activity public class ActivityStackManager { private Sta ...

  8. jquery 控制css样式

    一.CSS 1.css(name) 访问第一个匹配元素的样式属性. 返回值 String 参数 name (String) : 要访问的属性名称 示例: $("p").css(&q ...

  9. git学习一二三一

    svn用的多,但是我是一个geek,git这个美丽的scm,我怎能错过了?于是最近在全方位的窥视它的酮体,把我的一点心得分享给大家把. 先说一说给git的历史, Git是一个开源的分布式版本控制系统, ...

  10. 【Spark】Spark-foreachRDD需要注意的问题

    Spark-foreachRDD需要注意的问题 dstream.foreachRDD_百度搜索 通过Spark Streaming的foreachRDD把处理后的数据写入外部存储系统中 - 吾心光明 ...