当前位置: 首页 > news >正文

Entity Framework 并发处理(转)

什么是并发?

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

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

复制代码
public class 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.Entity<Person>().Property(p => p.RowVersion).IsRowVersion();

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

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

复制代码
       static void 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 N'update [dbo].[People]
set [LastName] = @0
where (([PersonId] = @1) and ([RowVersion] = @2))
select [RowVersion]
from [dbo].[People]
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来标识

复制代码
 public class Person
    {
        public int 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.Entity<Person>().Property(p => p.SocialSecurityNumber).IsConcurrencyToken();

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

复制代码
 static void 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 N'update [dbo].[People]
set [SocialSecurityNumber] = @0
where (([PersonId] = @1) and ([SocialSecurityNumber] = @2))
',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

转载于:https://www.cnblogs.com/ITGirl00/p/3533327.html

相关文章:

  • 总结 — 各种数据访问方式
  • 《海量空间数据库实施策略-栅格数据》PDF版本
  • WhyEngine游戏合集2014贺岁版
  • 基于属性的编辑器框架
  • Windows Phone 7 SDK 正式版本RTW
  • 解读Linux命令格式(转)
  • 通过手机摄像头实现动作追踪一----单帧的识别
  • PL/SQL Developer 9.x 注册码
  • 公司到底是怎么看我们的——Leo网上答疑47
  • Ext 2.2在IE 9运行居然说Ext-all.j运行错误,晕死了
  • 解决局域网文件共享设置
  • Socket 编程IO Multiplexing
  • Android 上传文件
  • [IE9] GPU硬件加速到底是实用创新还是噱头
  • ObjectUtils 类的方法
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 2017年终总结、随想
  • HTTP中的ETag在移动客户端的应用
  • JS基础之数据类型、对象、原型、原型链、继承
  • spring boot 整合mybatis 无法输出sql的问题
  • VuePress 静态网站生成
  • zookeeper系列(七)实战分布式命名服务
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 工程优化暨babel升级小记
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 巧用 TypeScript (一)
  • 思考 CSS 架构
  • 推荐一个React的管理后台框架
  • 学习HTTP相关知识笔记
  • linux 淘宝开源监控工具tsar
  • ​马来语翻译中文去哪比较好?
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • #Ubuntu(修改root信息)
  • (3)(3.5) 遥测无线电区域条例
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (论文阅读30/100)Convolutional Pose Machines
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转载)hibernate缓存
  • (转载)Linux 多线程条件变量同步
  • 、写入Shellcode到注册表上线
  • .NET Project Open Day(2011.11.13)
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET中的Exception处理(C#)
  • @for /l %i in (1,1,10) do md %i 批处理自动建立目录
  • @Transactional类内部访问失效原因详解
  • [AIGC] Java 和 Kotlin 的区别
  • [ajaxupload] - 上传文件同时附件参数值
  • [BZOJ 1040] 骑士
  • [BZOJ] 3262: 陌上花开
  • [bzoj4010][HNOI2015]菜肴制作_贪心_拓扑排序
  • [C#]猫叫人醒老鼠跑 C#的委托及事件
  • [EFI]Dell Inspiron 15 5567 电脑 Hackintosh 黑苹果efi引导文件
  • [flask] flask的基本介绍、flask快速搭建项目并运行
  • [Foreman]解决Unable to find internal system admin account