实体框架 – 并发
实体框架 – 并发
任何数据访问开发人员在回答有关数据并发性的问题时都会遇到困难,“如果多个人同时编辑相同的数据会怎样?”
-
我们当中比较幸运的人处理的业务规则是“没问题,最后一个获胜”。
-
在这种情况下,并发不是问题。更有可能的是,事情并没有那么简单,而且没有什么灵丹妙药可以一次性解决所有情况。
-
默认情况下,实体框架将采用“最后一个获胜”的路径,这意味着即使其他人在检索数据和保存数据之间更新了数据,也会应用最新的更新。
让我们举一个例子来更好地理解它。以下示例在 Course 表中添加了一个新列 VersionNo。
转到设计器并右键单击设计器窗口并选择从数据库更新模型…
您将看到在课程实体中添加了另一列。
右键单击新创建的列 VersionNo 并选择 Properties 并将 ConcurrencyMode 更改为 Fixed,如下图所示。
Course.VersionNo 的 ConcurrencyMode 设置为 Fixed,任何时候更新 Course,Update 命令都会使用它的 EntityKey 和它的 VersionNo 属性查找课程。
我们来看一个简单的场景。两个用户同时检索同一门课程,用户 1 将该课程的标题更改为 Maths 并在用户 2 之前保存更改。稍后,当用户 2 更改在用户 1 保存更改之前检索到的该课程的标题时,即案例用户 2 将获得并发异常“用户 2:发生乐观并发异常”。
using System; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Linq; namespace DatabaseFirstDemo { class Program { static void Main(string[] args) { Course c1 = null; Course c2 = null; //User 1 gets Course using (var context = new UniContextEntities()) { context.Configuration.ProxyCreationEnabled = false; c1 = context.Courses.Where(s ⇒ s.CourseID == 1).Single(); } //User 2 also get the same Course using (var context = new UniContextEntities()) { context.Configuration.ProxyCreationEnabled = false; c2 = context.Courses.Where(s ⇒ s.CourseID == 1).Single(); } //User 1 updates Course Title c1.Title = "Edited from user1"; //User 2 updates Course Title c2.Title = "Edited from user2"; //User 1 saves changes first using (var context = new UniContextEntities()) { try { context.Entry(c1).State = EntityState.Modified; context.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { Console.WriteLine("User1: Optimistic Concurrency exception occurred"); } } //User 2 saves changes after User 1. //User 2 will get concurrency exection //because CreateOrModifiedDate is different in the database using (var context = new UniContextEntities()) { try { context.Entry(c2).State = EntityState.Modified; context.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { Console.WriteLine("User2: Optimistic Concurrency exception occurred"); } } } } }