在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
本文介绍如何处理多个用户并发更新同一实 体(同时)时出现的冲突 。 主要是两种:一种,检查属性并发冲突,使用 [ConcurrencyCheck] ;另一种,检测行的并发冲突,使用 rowversion 跟踪属性,如果在保存之前有修改,就报错 发生并发冲突的情况: 1.用户导航到实体编辑页面; 2.第一个用户的更改还未写入数据库之前,另一个用户更新同一实体; 此时,如果未启用并发检测,当发生更新时: 最后一个更新优先。即最后一个更新的值保存到数据库。而第一个保存的值将丢失。 举个例子: 1. Jane 访问 院系 编辑页 面,将英 语 系的 预 算 从 350,000.00 美元更改 为 0.00 美元 (第一个用户把金额改为0) , 2. 在 Jane 单击 “ 保存 ” 之前, John 访问 了相同 页 面,并将开始日期字段从 2007/1/9 更改 为 2013/1/9。 (在第一个用户保存之前,第二个用户把时间从07年改为13年,注意此时第二个用户看到的金额还不是0) 3. Jane 先 单击 “ 保存 ” ,并在 浏览 器 显 示索引 页时 看到她的更改。 (第一个用户先保存,并且可以在浏览器看到他的修改,金额变0,时间不变) 4.John 单击 “ 编辑 ” 页 面上的 “ 保存 ” ,但 页 面的 预 算仍 显 示 为 350,000.00 美元。 (第二个用户保存,此时的页面的预算显示未350000美元,时间为13年) 其实这个结果取决于 并发冲突的处理方式 首先声明,这是一个乐观并发冲突,那么什么是乐观并发冲突呢? 乐观并发冲突允许发生并发冲突,并在并发冲突发生时作出正确的反映。 说了这么多,那么,并发冲突的处理方式呢? 1. 可以跟踪用户已修改的属性,并只更新数据库中相应的列。 这样,当两个用户更新了不同的属性,下次查看时,都将生效。 但是,这种方法,也有一些问题:
体现在例子中,就是如果 下次有人 浏览 英 语 系 时 ,将看到 Jane 和 John 两个人的更改。 2.客户端优先 即客户端的值优先于数据库存储的值。并且如果不对并发处理进行任何编码,将自动进行客户端优先 即John 的更改覆盖 Jane 的更改 。也就是说,下次有人 浏览 英 语 系 时 ,将看到 2013/9/1 和提取的 值 350,000.00 美元 3.存储优先 这种方式可以阻止在数据库中John的更改。并且可以
处理并发 当属性配置 为 并 发 令牌 时 :
数据库和数据模型必须配置为支持引发DbUpdateConcurrencyException 。 检测属性的并发冲突 可使用 ConcurrencyCheck 特性在属性级别检测并发冲突。 该特性可应用于模型上的多个属性 。[ConcurrencyCheck] 特性 检测行的并发冲突 要检测并发冲突,请将 rowversion 跟踪列添加到模型。 注意:rowversion , 1.它是 SQL Server 特定的。 其他数据库可能无法提供类似功能。 2.用于确定从数据库提取实体后未更改实体。 数据库生成rowversion序号,该数字随着每次行的更新递增。 在 update 或 delete 命令中,where 子句中包括 rowversion提取值 的判断 。 如果要更新的行已经修改,则 rowversion提取值与现在数据库中rowversion的值不匹配; update 或 delete 命令不能找到行。引发一个 DbUpdateConcurrencyException 异常 例子 向 Department 实 体添加跟踪属性 using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace ContosoUniversity.Models { public class Department { public int DepartmentID { get; set; } [StringLength(50, MinimumLength = 3)] public string Name { get; set; } [DataType(DataType.Currency)] [Column(TypeName = "money")] public decimal Budget { get; set; } [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] [Display(Name = "Start Date")] public DateTime StartDate { get; set; } public int? InstructorID { get; set; } 1644052793 public byte[] RowVersion { get; set; } //跟踪属性 public Instructor Administrator { get; set; } public ICollection<Course> Courses { get; set; } } } Timestamp 特性 指定此列包含在 update 和 delete 命令的 where 子句中。 也可以用 Fluent API 指定跟踪属性: modelBuilder.Entity<Department>() .Property<byte[]>("RowVersion") .IsRowVersion(); 以下代 码显 示更新 Department 名称 时 由 EF Core 生成的部分 T-SQL : SET NOCOUNT ON; UPDATE [Department] SET [Name] = @p0 WHERE [DepartmentID] = @p1 AND [RowVersion] = @p2; SELECT [RowVersion] FROM [Department] WHERE @@ROWCOUNT = 1 AND [DepartmentID] = @p1; 前面的 代 码显 示包含 RowVersion 的 WHERE 子句。 如果数据 库 RowVersion 不等于 RowVersion 参数( @p2 @@ROWCOUNT 返回受上一 语 句影响的行数。 在没有行更新的情况下, EF Core 引 发 此文主要是为了方便自己记录学习,如有错误,欢迎指正 这里附上参考资料: 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持极客世界。
|
请发表评论