使用EFCore处理并发冲突
一、首先添加并发处理标记
在需要进行并发处理的类中添加版本号,并在版本号上使用[Timestamp]标记:
public class Department
{
public int Id { get; set;}
public ……
public int? InstructorId{ get; set; }
public ICollection<Course> Courses {get; set; }
//版本号
[Timestamp]
public byte[] RowVersion{get; set; }
}
二、然后更新数据库
add-migration updateTimestampForDeparment
update-database
三、重新建基架项目
删除Create和Edit页面内关于RowVersion项目的输入项
四、打开编辑Edit的控制器,修改如下:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int? id, byte[]rowVersion)
{
if(id==null)
{
return NoFound();
}
//先查一下数据是否存在
var department= await
_context.Departments.Include(a=>a.Administrator)
.SingleOrDefaultAsync(a=>a.Id==id); if(department==null)
{
var deletedDepartment = new Department();
await TryUpdateModeAsync(deletedDepartment);
ModelState.AddModelError(string.Empty,"无法进行数据的修改,该部门信息已经被其他人删除!);
ViewBag.InstructorId = new SelectList(_context.Instructors, "Id","RealName",deletedDepartment);
return View(deletedDepartment);
} //将RowVersion标志原来的值变更为新的值
_context.Entry(department).Property("RowVersion").OriginalValue = rowVersion; if(await TryUpdateModelAsync<Department>(department, a=>a.Name, a=>a.StartDate, a=>a.Budge(a=>a.InstructorId))
{
try
{
await _context.SaveChangesAsync();
return RedireToAction(nameof(Index));
}
catch(DbUpdateException ex)
{
var exceptionEntity = ex.Entries.Single();
var clienValue = (Department)exceptionEntity.Entity; var databaseEntity = exceptionEntity.GetDatabaseValues();
if(databaseEntity == null)
{
ModelState.AddModelError(string.Empty, "无法进行数据的修改,该部门信息已经被其他人删除!);
}
else{
var databaseValues=(Dapartment)databaseEntity.ToObject();
if(databaseValues.Budget != clienValue.Budget)
{
ModelState.AddModelErrow("Budget", $"当前值:{databaseValues.Budget}");
}
if(databaseValues.StartDate != clienValue.StartDate)
{
ModelState.AddModelErrow("StartDate", $"当前值:{databaseValues.StartDate}");
}
if(databaseValues.InstructorId != clienValue.InstructorId)
{
var instructorEntity = await _context.Instructors.SingleOrDfaultAsync(a=>a.Id == databaseValues.InstructorId);
ModelState.AddModelErrow("InstructorId", $"当前值:{instructorEntity?.RealName}");
}
ModelState.AddModelErrow("", "你正在编辑的记录已经被其他用户所修改,编辑操作已经被取消,数据库当前的值已经显示在页面,请再次点击保存。否则请返回列表"); department.RowVersion=(byte[])databaseValues.RowVersion;
ModelState.Remove("RowVersion");
}
}
}
ViewBag.InstructorId=new SelectList(_context.Instructors, "Id","RealName",deletedDepartment) return View(department);
}
五、修改Edit视图
添加版本号字段到Form中
<input type="hidden" asp-for="RowVersion" />
六、修改删除控制器
public async Task<IActionResult> Delete(int? id, bool? concurrencyError)
{
if( id == null)
{
return NotFound();
} var department = await _context.Departments
.include(d=>d.Administrator).AsNoTracking()
.singleOrDefaultAsync(m=>m.Id==id);
if(department == null)
{
if(concurrencyError.GetValueOrDefault());
{
return RedirectToAction(nameof(Index));
}
return NotFound();
} if(concurrencyError.GetValueOrDefault());
{
ViewBag.concurrencyErrow = "你正在删除的信息,已经被别人修改了,当前操作会被取消,如果你要继续删除该条信息,请重新点击删除按钮,否则请返回列表";
} return View(department);
}
七、修改删除确认控制器
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(Department department)
{
try
{
if(await _context.Departments.AnyAsync(a=>a.Id==department.id)
{
_context.Departments.Remove(department);
await _context.SaveChangesAsync();
}
return RedirectToAction(nameof(Index));
}
catch(DbUpdateException e)
{
return RedirectToAction(nameof(Delete),new {concurrencyError = true, id = department.Id});
}
}
八、修改删除视图
在视图中添加报错信息的显示块:
<p class="text-denger">@Viewbag.</p>
使用EFCore处理并发冲突的更多相关文章
- Linq to Sql : 并发冲突及处理策略
原文:Linq to Sql : 并发冲突及处理策略 1. 通过覆盖数据库值解决并发冲突 try { db.SubmitChanges(ConflictMode.ContinueOnConflict) ...
- LINQ-to-SQL那点事~LINQ-to-SQL中的并发冲突与应对
回到目录 在上一篇文章中提到了并发冲突,还说详细的说明在这讲来说,呵呵,那现在就说一下吧! 并发冲突产生的原因 事实上,linq to sql中的并发冲突是指记录在进行update操作时,客户端A1取 ...
- Mego开发文档 - 处理并发冲突
处理并发冲突 数据库并发是指多个进程或用户同时访问或更改数据库中的相同数据的情况.并发控制是指用于确保存在并发更改时数据一致性的特定机制. Mego实现了乐观并发控制,这意味着它可以让多个进程或用户独 ...
- asp.net core 系列之并发冲突
本文介绍如何处理多个用户并发更新同一实体(同时)时出现的冲突 . 主要是两种:一种,检查属性并发冲突,使用 [ConcurrencyCheck] ;另一种,检测行的并发冲突,使用 rowversion ...
- MySQL事物(一)事务隔离级别和事物并发冲突
数据库的操作通常为写和读,就是所说的CRUD:增加(Create).读取(Read).更新(Update)和删除(Delete).事务就是一件完整要做的事情.事务是恢复和并发控制的基本单位.事务必须始 ...
- Linq to Sql并发冲突及处理策略
0. 并发冲突的示例 单用户的系统现在应该比较罕见了,一般系统都会有很多用户在同时进行操作:在多用户系统中,涉及到的一个普遍问题:当多个用户“同时”更新(修改或者删除)同一条记录时,该如何更新呢? ...
- C# 开放式并发冲突报错处理
1.调用DataSet.GetChanges()获取数据源中改变的数据 var data = ViewData.GetChanges() as ReleaseData; 2.为新增的数据 data 加 ...
- Elasticsearch由浅入深(四)ES并发冲突、悲观锁与乐观锁、_version乐观锁并发
ES并发冲突 举个例子,比如是电商场景下,假设说,我们有个程序,工作的流程是这样子的: 读取商品信息(包含了商品库存) 用户下单购买 更新商品信息(主要是将库存减1) 我们比如咱们的程序就是多线程的, ...
- 分布式缓存重建并发冲突和zookeeper分布式锁解决方案
如果缓存服务在本地的ehcache中都读取不到数据. 这个时候就意味着,需要重新到源头的服务中去拉去数据,拉取到数据之后,赶紧先给nginx的请求返回,同时将数据写入ehcache和redis中 分布 ...
随机推荐
- js可拖拽的div
function chatDrag(div1) { div1.onmousedown = function (ev) { var oevent = ev || event; var distanceX ...
- Qt551.窗口滚动条
1.代码的方式来创建 ScrollArea,然后使用 倒是 正常(有滚动条显示),但是此方式太麻烦 不如直接拖控件来的方便直观快捷. 但是,直接拖控件的方式 ScrollArea中无法显示出 滚动条, ...
- 多重if-else语句
C语言自学之多重if-else语句 Dome : 某游戏对不同等级的积分的玩家赋予不同的荣誉称号,其对应关系如下: 积分>=10000分为钻石玩家 积分>=5000并且<10000为 ...
- 在ibatis中时间段查询完整代码
ibatis.xml文件中的代码如下: <typeAlias alias="ServInvokeTest" type="com.entity.ServInvokeT ...
- python learn note1
1.python 的缩进 习惯了java,c++之类的宽容,初学python,被它摆了道下马威,写if else,竟然必须要我正确用缩进格式,原来在python里不能用括号来表示语句块,也不能用开始/ ...
- CQRS粗浅理解
CQRS(命令查询责任分离)是一种奇特的模式,表示解耦系统的输入和输出. 通常情况下,输入端将数据写到数据库,输出端从数据库查询.与读写锁的场景类似,写的过程中不能读.正常情况下没有问题,但是在大规模 ...
- Java正则表达式实现港、澳、台身份证验证
最近由于业务的要求,需要进行港.澳.台人员身份证验证,现在直接上代码,经供参考学习,也为自己积累一些工具类: package com.qiu.validate; public class regexV ...
- js判断一个字符串是否是回文字符串
回文字符串:即字符串从前往后读和从后往前读字符顺序是一致的. 如:字符串abccba,从前往后读是a-b-c-c-b-a:从后往前读也是a-b-c-c-b-a 方法一 function palindR ...
- week6
面向对象编程 class类(新式类:class xx(obj):,经典类 class xx:) 构造函数 __init__(self,ret1,ret2...) 在实例化时做一些类的初始化工作 析构函 ...
- arp嗅探(windows)
本次实验环境:windows本次实验工具:cain汉化版1.点击配置,嗅探器里选一个适配器,点击确定. 2.点击 3.扫描mac地址 4.点击ARP->嗅探器->添加到列表5.点击开始嗅探 ...