本文介绍了当多个用户同时更新同一个实体时,如何处理冲突。
主要有两种类型:一种是检查属性的并发冲突,使用[concurrency check];另一方面,为了检测行的并发冲突,使用了rowversion跟踪属性,如果在保存之前有任何修改,就会报告一个错误
并发冲突的情况:
1.用户导航到实体编辑页面;
2.在第一个用户的更改被写入数据库之前,另一个用户更新相同的实体;
此时,如果未启用并发检测,当更新发生时:
最后一次更新优先。也就是说,最后更新的值保存到数据库中。第一个保存的值将会丢失。
例如:
1.Jane访问了部门的编辑页面,将英文部门的预先计算从$350,000.00更改为$0.00(第一个用户将金额更改为0)
,
2.在Jane单击Save之前,John访问了同一个页面,并将开始日期字段从2007年1月9日更改为2013年1月9日。(在第一个用户保存之前,第二个用户将时间从2007年更改为13年。注意,第二个用户看到的金额还不是0。)
3.Jane首先单击“保存”,当浏览器显示索引页面时,她会看到自己的更改。(第一个用户先保存,可以在浏览器中看到他的修改,金额变为0,时间不变)
4.约翰点击“编辑”页面上的“保存”,但页面的预计算仍显示为$350,000.00。(第二个用户保存,此时页面预算显示没有35万美元,时间是13年)
事实上,这个结果取决于并发冲突的处理
首先,这是一个乐观并发冲突,那么什么是乐观并发冲突呢?
乐观并发冲突允许并发冲突发生,并在并发冲突发生时做出正确的响应。
话虽如此,如何处理并发冲突?
1.您可以跟踪用户修改的属性,并且只更新数据库中相应的列。
这样,当两个用户更新不同的属性时,下次查看时就会生效。
但是,这种方法也有一些问题:
当相同的属性发生竞争变化时,数据丢失是无法避免的,这通常不适合web应用程序。它需要保持一个重要的状态,以便跟踪所有提取的和新的值。保持大量状态可能会影响应用程序性能。它可能会增加应用程序的复杂性(与实体上的并发检测相比)。例如,如果有人下次浏览英语系,他们会看到简和约翰所做的更改。
2.客户至上
也就是说,客户端的值优先于数据库中存储的值。而且如果你不编码并发处理,你会自动优先考虑客户端
也就是说,约翰的改变压倒了简的改变。换句话说,下一次有人浏览英语系,就会看到2013/9/1和提取的价值350,000.00美元
3.存储优先级
这种方式可以防止约翰在数据库中更改。五月
显示错误消息显示数据的当前状态,允许用户重新应用更改。处理并发性
当属性被配置为并发发送令牌时:
数据库和数据模型必须配置为支持抛出DbUpdateConcurrencyException。
检测属性的并发冲突
您可以使用ConcurrencyCheck属性来检测属性级别的并发冲突。该属性可以应用于模型的多个属性。[并发检查]属性
检测行中的并发冲突
若要检测并发冲突,请将rowversion跟踪列添加到模型中。
注意:rowversion,
1.它是特定于SQL Server的。其他数据库可能不提供类似的功能。
2.它用于确定实体从数据库中提取后没有发生变化。
数据库生成rowversion序列号,该序列号随着每次行更新而增加。
在更新或删除命令中,where子句包含对rowversion的判断,以提取值。
如果要更新的行已被修改,则提取的rowversion值与当前数据库中的rowversion值不匹配;
更新或删除命令找不到该行。引发了DbUpdateConcurrencyException异常
例子
向部门实体添加跟踪属性
使用系统;使用系统。集合。通用;使用系统。组件模型。数据注释;使用系统。组件模型。数据注释。模式;命名空间控制大学。模型{公共类部门{ public int Department id { get设置;}[字符串长度(50,最小长度=3)]公共字符串名称{获取设置;}[DataType(数据类型。货币)][列(类型名='货币')]公共十进制预算{获取设置;}[DataType(数据类型。日期)][显示格式(数据格式字符串='{0:yyyy-MM-dd} ',应用格式编辑模式=真)][显示(名称='开始日期')]公共日期时间开始日期{获取;设置;}public int?InstructorID { get设置;} 1585924210公共字节[]行版本{ get设置;} //跟踪属性公共讲师管理员{获取设置;}公共ICollectionCourse课程{获取设置;} } }时间戳特性指定此列包含在更新和删除命令的在哪里子句中。
也可以用流畅的应用编程接口指定跟踪属性:
模型构建器EntityDepartment().属性字节[](“行版本”).ISR over ion();以下代码显示更新部门名称时由英孚核心生成的部分T-SQL:
设置无计数开启;更新[部门]集合[名称]=@ p0WHERE[部门id]=@ P1和[行版本]=@ p2;从[部门]中选择[行版本],其中@ @行计数=1且[部门标识]=@ P1;前面的代码显示包含时间戳的在哪里子句。如果数据库时间戳不等于时间戳参数(@p2),则不更新行。
@@ROWCOUNT返回受上一语句影响的行数。在没有行更新的情况下,英孚核心引发DbUpdateConcurrencyException
此文主要是为了方便自己记录学习,如有错误,欢迎指正
这里附上参考资料:
https://个医生。微软。com/en-us/aspnet/core/data/ef-RP/并发?view=aspnetcore-2.2 tas=visual-studio
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
英孚核心验证提取属性后是否未更改属性。调用保存更改或保存更改同步时会执行此检查。如果提取属性后更改了属性,将引发DbUpdateConcurrencyException。