什么是并发?

并发分悲观并发和乐观并发。

悲观并发:比如有两个用户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[]类型。

  1. public class Person
  2. {
  3. public int PersonId { get; set; }
  4. public int SocialSecurityNumber { get; set; }
  5. public string FirstName { get; set; }
  6. public string LastName { get; set; }
  7. [Timestamp]
  8. public byte[] RowVersion { get; set; }
  9. }

Fluent API用IsRowVersion方法

  1. modelBuilder.Entity<Person>().Property(p => p.RowVersion).IsRowVersion();

我们看到生成的数据库中,RowVersion是timestamp类型。

下面我们写一段代码来测试一下:

  1. static void Main(string[] args)
  2. {
  3. var person = new Person
  4. {
  5. FirstName = "Rowan",
  6. LastName = "Miller",
  7. SocialSecurityNumber = 12345678
  8. };
  9. //新增一条记录,保存到数据库中
  10. using (var con = new BreakAwayContext())
  11. {
  12. con.People.Add(person);
  13. con.SaveChanges();
  14. }
  15.  
  16. var firContext = new BreakAwayContext();
  17. //取第一条记录,并修改一个字段:这里是修改了FirstName
  18. //先不保存
  19. var p1 = firContext.People.FirstOrDefault();
  20. p1.FirstName = "Steven";
  21.  
  22. //再创建一个Context,同样取第一条记录,修改LastName字段并保存
  23. using (var secContext = new BreakAwayContext())
  24. {
  25. var p2 = secContext.People.FirstOrDefault();
  26. p2.LastName = "Francis";
  27. secContext.SaveChanges();
  28. }
  29. try
  30. {
  31. firContext.SaveChanges();
  32. Console.WriteLine(" 保存成功");
  33. }
  34. catch (DbUpdateConcurrencyException ex)
  35. {
  36. Console.WriteLine(ex.Entries.First().Entity.GetType().Name + " 保存失败");
  37. }
  38. Console.Read();
  39. }

上面我们实例化了三个DbContext,第一个增加一条记录到数据库中,第二个修改刚增加的记录但不保存,然后第三个Context也取刚新增的记录并保存,最后再保存第二个Context,结果保存失败。

可以看到我们的并发控制取到了作用。

分析EF生成的SQL语句:

  1. exec sp_executesql N'update [dbo].[People]
  2. set [LastName] = @0
  3. where (([PersonId] = @1) and ([RowVersion] = @2))
  4. select [RowVersion]
  5. from [dbo].[People]
  6. where @@ROWCOUNT > 0 and [PersonId] = @1',N'@0 nvarchar(max) ,@1 int,@2 binary(8)',@0=N'Francis',@1=1,@2=0x00000000000007D1

可以看到,它在取对应记录的时候把RowVersion也作为筛选条件。上面例子中的secContext保存的时候,数据库中的RowVersion字段的值就变了,所以firContext保存的时候用原来的RowVersion取值,自然就取不到相应的记录而报错。

如果我们只是要对某个字段作并发控制呢?别着急,EF也有办法。

Data Annotations中用ConcurrencyCheck来标识

  1. public class Person
  2. {
  3. public int PersonId { get; set; }
  4. [ConcurrencyCheck]
  5. public int SocialSecurityNumber { get; set; }
  6. public string FirstName { get; set; }
  7. public string LastName { get; set; }
  8. public byte[] RowVersion { get; set; }
  9. }

Fluent API用IsConcurrencyToken方法

  1. modelBuilder.Entity<Person>().Property(p => p.SocialSecurityNumber).IsConcurrencyToken();

上面的实体中,我们将SocialSecurityNumber(社会保险号)标识为开放式并发,也写一个类似的代码测试一下:

  1. static void Main(string[] args)
  2. {
  3. var person = new Person
  4. {
  5. FirstName = "Rowan",
  6. LastName = "Miller",
  7. SocialSecurityNumber = 12345678
  8. };
  9. //新增一条记录,保存到数据库中
  10. using (var con = new BreakAwayContext())
  11. {
  12. con.People.Add(person);
  13. con.SaveChanges();
  14. }
  15.  
  16. var firContext = new BreakAwayContext();
  17. //取第一条记录,并修改SocialSecurityNumber字段
  18. //先不保存
  19. var p1 = firContext.People.FirstOrDefault();
  20. p1.SocialSecurityNumber = 123;
  21.  
  22. //再创建一个Context,同样取第一条记录,
  23. //修改SocialSecurityNumber字段并保存
  24. using (var secContext = new BreakAwayContext())
  25. {
  26. var p2 = secContext.People.FirstOrDefault();
  27. p2.SocialSecurityNumber = 456;
  28. secContext.SaveChanges();
  29. }
  30. try
  31. {
  32. firContext.SaveChanges();
  33. Console.WriteLine(" 保存成功");
  34. }
  35. catch (DbUpdateConcurrencyException ex)
  36. {
  37. Console.WriteLine(ex.Entries.First().Entity.GetType().Name + " 保存失败");
  38. }
  39. Console.Read();
  40. }

运行结果同样是保存失败,说明我们的并发控制起作用了。

分析一下EF执行的SQL:

  1. exec sp_executesql N'update [dbo].[People]
  2. set [SocialSecurityNumber] = @0
  3. where (([PersonId] = @1) and ([SocialSecurityNumber] = @2))
  4. ',N'@0 int,@1 int,@2 int',@0=123,@1=1,@2=12345678

可以看到,EF将我们要并发控制的列SocialSecurityNumber也作为一个筛选条件,这样firContext保存的时候也会因为的数据库中SocialSecurityNumber值变了,取不到对应的记录而更新失败。

补充一下:如果是EDMX如何将字段设置为Concurrency。很简单,在对应的字段上右键-属性。在打开的属性窗口中有一个并发模式,你将它选择为Fixed即可。

转:http://www.cnblogs.com/Gyoung/archive/2013/01/18/2866649.html

Entity Framework 并发处理(转)的更多相关文章

  1. C# Entity Framework并发处理

    原网站:C# Entity Framework并发处理 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的错误的一种机制.从 ADO.NET 到 LINQ to SQL 再到如今的 ADO.NE ...

  2. [转]C#综合揭秘——Entity Framework 并发处理详解

    本文转自:http://www.cnblogs.com/leslies2/archive/2012/07/30/2608784.html 引言 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的 ...

  3. C#综合揭秘——Entity Framework 并发处理详解

    引言 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的错误的一种机制.从 ADO.NET 到 LINQ to SQL 再到如今的 ADO.NET Entity Framework,.NET 都 ...

  4. Entity Framework 并发处理

    什么是并发? 并发分悲观并发和乐观并发. 悲观并发:比如有两个用户A,B,同时登录系统修改一个文档,如果A先进入修改,则系统会把该文档锁住,B就没办法打开了,只有等A修改完,完全退出的时候B才能进入修 ...

  5. Entity Framework 并发处理借鉴

    如下博客 http://www.cnblogs.com/Bce-/p/3725868.html

  6. Entity Framework 乐观并发控制

    一.背景 我们知道,为了防止并发而出现脏读脏写的情况,可以使用Lock语句关键字,这属于悲观并发控制的一种技术,,但在分布式站点下,锁的作用几乎不存在,因为虽然锁住了A服务器的实例对象,但B服务器上的 ...

  7. C#:ORM--实体框架EF(entity framework)(1)

    本文来自:http://www.cnblogs.com/xuf22/articles/5513283.html 一.什么是ORM ORM(Object-relational mapping),中文翻译 ...

  8. Entity Framework 项目使用心得

    在博客园很久了,一直只看不说,这是发布本人的第一个博客. 总结一下在项目中,EntityFramework使用的一下经验拿来和大家分享,希望对大家有用~ 1.         在Entity Fram ...

  9. Entity Framework知识小总结

    什么是Entity Framework EF是微软主推的数据存取技术,在实际开发中,现在通常使用EF来构建应用程序的数据存取层,它是一个开源的“对象/关系映射(ORM:Object Relationa ...

随机推荐

  1. Spring装配Bean的过程

    首先说一个概念:“懒加载” 懒加载:就是我们在spring容器启动的是先不把所有的bean都加载到spring的容器中去,而是在当需要用的时候,才把这个对象实例化到容器中. spring配置文件中be ...

  2. 管理开机启动:systemd

    一.CentOS7 systemd 介绍 在 CentOS7 中,使用 systemd 来管理其他服务是否开机启动,systemctl 是 systemd 服务的命令行工具 [root@localho ...

  3. PyQt4消息窗口

    默认情况下,如果我们单击了窗口标题栏上的X标记,窗口就会被关闭.但是有些时候我们想要改变这一默认行为.比如,我们正在编辑的文件内容发生了变化,这时若单击X标记关闭窗口,编辑器就应当但出确认窗口. #! ...

  4. cocos2dx游戏--欢欢英雄传说--添加攻击按钮

    接下来添加攻击按钮用于执行攻击动作.同时修复了上一版移动时的bug.修复后的Player::walkTo()函数: void Player::walkTo(Vec2 dest) { if (_seq) ...

  5. cocos2dx3.1从零学习(二)菜单、场景切换、场景传值

    转:http://www.it165.net/pro/html/201406/16195.html 回顾一下上一篇的内容,我们已经学会了创建一个新的场景scene,添加sprite和label到层中, ...

  6. IDEA 配置

    配置sublime主题: 击链接 http://www.riaway.com,选择并下载自己喜欢的主题 file -->import setting  到刚刚下载的主题jar包,之后导入,重起i ...

  7. OC开发_Storyboard——iPad开发

    iPad开发(Universal Applications) 一.iPad 1.判断是否在iPad上 BOOL iPad = ([[UIDevice currentDevice] userInterf ...

  8. rman备份的其它特性

    1.7.3.1并发: 主要用于提高备份的速度,可以分为手动并发或自动并发 手动并发:通过分配多个通道并将文件指定到特定的通道 RMAN> run { 2>  allocate channe ...

  9. RMAN备份详解

    1.7.1数据库备份与RMAN备份的概念 1.数据库完全备份:按归档模式分为归档和非归档 归档模式 打开状态,属于非一致性备份 关闭状态,可以分为一致性和非一致性 非归档模式 打开状态,非一致性备份无 ...

  10. 最小树形图(poj3164)

    Command Network Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 12834   Accepted: 3718 ...