网站建设策划模板,网站是专门对生活中的一些所谓常识做辟谣的,做网站的属于什么专业?,网络运营培训哪里有学校ef 并发控制 ef 并发控制 什么是并发#xff1f;并发分悲观并发和乐观并发。悲观并发#xff1a;比如有两个用户A,B#xff0c;同时登录系统修改一个文档#xff0c;如果A先进入修改#xff0c;则系统会把该文档锁住#xff0c;B就没办法打开了#xff0c;只有等A修改完… ef 并发控制 ef 并发控制 什么是并发 并发分悲观并发和乐观并发。 悲观并发比如有两个用户A,B同时登录系统修改一个文档如果A先进入修改则系统会把该文档锁住B就没办法打开了只有等A修改完完全退出的时候B才能进入修改。 乐观并发同上面的例子A,B两个用户同时登录如果A先进入修改紧跟着B也进入了。A修改文档的同时B也在修改。如果在A保存之后B再保存他的修改此时系统检测到数据库中文档记录与B刚进入时不一致B保存时会抛出异常修改失败。 EF中如何控制并发 Entity Framework不支持悲观并发只支持乐观并发。 如果要对某一个表做并发处理就在该表中加一条Timestamp类型的字段。注意一张表中只能有一个Timestamp的字段。 Data Annotations中用Timestamp来标识设置并发控制字段标识为Timestamp的字段必需为byte[]类型。 publicclass Person { public int PersonId { get; set; } public int SocialSecurityNumber { get; set; } public string FirstName { get; set; } public string LastName { get; set; } [Timestamp] public byte[] RowVersion { get; set; } } Fluent API用IsRowVersion方法 modelBuilder.EntityPerson().Property(p p.RowVersion).IsRowVersion(); 我们看到生成的数据库中RowVersion是timestamp类型。 下面我们写一段代码来测试一下 staticvoid Main(string[] args) { var person new Person { FirstName Rowan, LastName Miller, SocialSecurityNumber 12345678 }; //新增一条记录保存到数据库中using (var con new BreakAwayContext()) { con.People.Add(person); con.SaveChanges(); } var firContext new BreakAwayContext(); //取第一条记录,并修改一个字段这里是修改了FirstName //先不保存var p1 firContext.People.FirstOrDefault(); p1.FirstName Steven; //再创建一个Context同样取第一条记录修改LastName字段并保存using (var secContext new BreakAwayContext()) { var p2 secContext.People.FirstOrDefault(); p2.LastName Francis; secContext.SaveChanges(); } try { firContext.SaveChanges(); Console.WriteLine( 保存成功); } catch (DbUpdateConcurrencyException ex) { Console.WriteLine(ex.Entries.First().Entity.GetType().Name 保存失败); } Console.Read(); } 上面我们实例化了三个DbContext,第一个增加一条记录到数据库中第二个修改刚增加的记录但不保存然后第三个Context也取刚新增的记录并保存最后再保存第二个Context结果保存失败。 可以看到我们的并发控制取到了作用。 分析EF生成的SQL语句 exec sp_executesql Nupdate [dbo].[People] set [LastName] 0 where (([PersonId] 1) and ([RowVersion] 2)) select [RowVersion] from [dbo].[People] where ROWCOUNT 0 and [PersonId] 1,N0 nvarchar(max) ,1 int,2 binary(8),0NFrancis,11,20x00000000000007D1 可以看到它在取对应记录的时候把RowVersion也作为筛选条件。上面例子中的secContext保存的时候数据库中的RowVersion字段的值就变了所以firContext保存的时候用原来的RowVersion取值自然就取不到相应的记录而报错。 如果我们只是要对某个字段作并发控制呢别着急EF也有办法。 Data Annotations中用ConcurrencyCheck来标识 public class Person { publicint PersonId { get; set; } [ConcurrencyCheck] public int SocialSecurityNumber { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public byte[] RowVersion { get; set; } } Fluent API用IsConcurrencyToken方法 modelBuilder.EntityPerson().Property(p p.SocialSecurityNumber).IsConcurrencyToken(); 上面的实体中我们将SocialSecurityNumber(社会保险号)标识为开放式并发也写一个类似的代码测试一下 staticvoid Main(string[] args) { var person new Person { FirstName Rowan, LastName Miller, SocialSecurityNumber 12345678 }; //新增一条记录保存到数据库中using (var con new BreakAwayContext()) { con.People.Add(person); con.SaveChanges(); } var firContext new BreakAwayContext(); //取第一条记录,并修改SocialSecurityNumber字段 //先不保存var p1 firContext.People.FirstOrDefault(); p1.SocialSecurityNumber 123; //再创建一个Context同样取第一条记录 //修改SocialSecurityNumber字段并保存using (var secContext new BreakAwayContext()) { var p2 secContext.People.FirstOrDefault(); p2.SocialSecurityNumber 456; secContext.SaveChanges(); } try { firContext.SaveChanges(); Console.WriteLine( 保存成功); } catch (DbUpdateConcurrencyException ex) { Console.WriteLine(ex.Entries.First().Entity.GetType().Name 保存失败); } Console.Read(); } 运行结果同样是保存失败说明我们的并发控制起作用了。 分析一下EF执行的SQL exec sp_executesql Nupdate [dbo].[People] set [SocialSecurityNumber] 0 where (([PersonId] 1) and ([SocialSecurityNumber] 2)) ,N0 int,1 int,2 int,0123,11,212345678 可以看到EF将我们要并发控制的列SocialSecurityNumber也作为一个筛选条件这样firContext保存的时候也会因为的数据库中SocialSecurityNumber值变了取不到对应的记录而更新失败。 补充一下如果是EDMX如何将字段设置为Concurrency。很简单在对应的字段上右键-属性。在打开的属性窗口中有一个并发模式你将它选择为Fixed即可。 posted on 2018-08-10 22:45 micwin 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/chinanetwind/articles/9457873.html