博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何处理Entity Framework中的DbUpdateConcurrencyException异常
阅读量:7182 次
发布时间:2019-06-29

本文共 4755 字,大约阅读时间需要 15 分钟。

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.}

 

 

本文转自JustRun博客园博客,原文链接:http://www.cnblogs.com/JustRun1983/archive/2012/10/10/2717891.html,如需转载请自行联系原作者

你可能感兴趣的文章
Linux Systemcall By INT 0x80、Llinux Kernel Debug Based On Sourcecode
查看>>
imageNamed 与 imageWithContentsOfFile的区别
查看>>
【Mysql 调用存储过程,输出参数的坑】
查看>>
LCS算法
查看>>
COM结构化存储中存储对象或者流对象的命名规则
查看>>
iOS开发基础知识--碎片26
查看>>
制作鼠标移动到div上面显示弹出框
查看>>
java既然存在gc线程,为什么还存在内存泄漏?
查看>>
Linux Vim
查看>>
UVA - 11987 Almost Union-Find[并查集 删除]
查看>>
使用css开启硬件加速提高网站性能
查看>>
CMakeLists.txt的写法
查看>>
Flask如何使用https?
查看>>
Linux命令之kill
查看>>
Asp.Net SignalR Hub类中的操作详解
查看>>
附上解决迅雷9及迅雷极速版任何资源下载任务出错、内容违规问题
查看>>
hadoop3: mkdir: cannot create directory `/usr/local/hadoop/bin/../logs’: Permission denied
查看>>
高阶函数与面向对象继承的比较
查看>>
群雄逐鹿的移动互联网时代【转载】
查看>>
【排序】InsertSort
查看>>