如何处理Entity Framework中的DbUpdateConcurrencyException异常
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异常的更多相关文章
- 如何处理Entity Framework / Entity Framework Core中的DbUpdateConcurrencyException异常(转载)
1. Concurrency的作用 场景有个修改用户的页面功能,我们有一条数据User, ID是1的这个User的年龄是20, 性别是female(数据库中的原始数据)正确的该User的年龄是25, ...
- 在Entity Framework中使用事务
继续为想使用Entity Framework的朋友在前面探路,分享的东西虽然技术含量不高,但都是经过实践检验的. 在Entity Framework中使用事务很简单,将操作放在TransactionS ...
- Entity Framework 教程——Entity Framework中的实体类型
Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...
- 关于Entity Framework中的Attached报错相关解决方案的总结
关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...
- 关于Entity Framework中的Attached报错的完美解决方案终极版
之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...
- [转]在Entity Framework中使用LINQ语句分页
本文转自:http://diaosbook.com/Post/2012/9/21/linq-paging-in-entity-framework 我们知道,内存分页效率很低.并且,如果是WebForm ...
- Entity Framework中的多个库操作批量提交、事务处理
在Entity Framework 中使用SaveChanges()是很频繁的,单次修改或删除数据后调用SaveChanges()返回影响记录数. 要使用批量修改或者批量删除数据,就需要SaveCha ...
- LinqToSql和ASP.NET Entity FrameWork 中使用事务
ASP.NET Entity FrameWork中: int flag = -1; if (this.URPmanagementEntities1.Connection.State != System ...
- Lazy<T>在Entity Framework中的性能优化实践
Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...
随机推荐
- npm出错的解决方案
npm show grpc # 返回版本号 # 安装旧版本: npm install grpc@1.2.0
- probotuf 标量数值类型
标量数值类型 一个标量消息字段可以含有一个如下的类型--该表格展示了定义于.proto文件中的类型,以及与之对应的.在自动生成的访问类中定义的类型: .proto类型 Java 类型 C++类型 备注 ...
- gunicorn结合django启动后台线程
preload 为True的情况下,会将辅助线程或者进程开在master里,加重master的负担(master最好只是用来负责监听worker进程) django应用的gunicorn示例:只在主线 ...
- Android studio 编译失败Error:Could not read entry ':app:processDebugManifest' from cache taskArtifacts.b
Android studio 编译失败 Error:Could not read entry ':app:processDebugManifest' from cache taskArtifacts. ...
- Python实现爬虫设置代理IP和伪装成浏览器的方法(转载)
https://www.jb51.net/article/139587.htm chrome_options = webdriver.ChromeOptions() chrome_options.ad ...
- 【Kafka】Kafka-配置参数详解-参数调优
Kafka-配置参数详解-参数调优 kafka 目录_百度搜索 为什么kafka使用磁盘而不是内存 - CSDN博客 Kafka 配置说明 - 風吹云动 - 博客园 kafka生产服务器配置 - Or ...
- Deep Learning 教程(斯坦福深度学习研究团队)
http://www.zhizihua.com/blog/post/602.html 说明:本教程将阐述无监督特征学习和深度学习的主要观点.通过学习,你也将实现多个功能学习/深度学习算法,能看到它们为 ...
- GIF添加3D加速
由于浏览器内核对Gif格式的图片会产生卡的情况,所以我们需要告诉浏览器,开启一下加速,方法很简单,就是利用css3的特性,强制告诉浏览器,这是个元素,需要3D转换,请务必开启加速效果 方法1 给gif ...
- Sublime Es6教程1-环境搭建
因为现在网上的教程都不靠谱,于是决定自己跳坑自己写,分为三块来玩: 一.环境搭建 二.语法讲解 三.项目实战 很多时候,你想搞一个东西,却因为环境没有搭建好,而不能很开森的探索未知的世界,多年的编程经 ...
- 解决input框中加入disabled="disabled"之后,改变字体的颜色(默认的是灰色)
在input框中加入disabled="disabled"之后,字体默认的就变成灰色了 解决方案 input[disabled]{color:#fff;opacity:1} dis ...