MySQL 实现 EF Code First TimeStamp/RowVersion 并发控制
在将项目迁移到MySQL 5.6.10数据库上时,遇到和迁移到PostgreSQL数据库相同的一个问题,就是TimeStamp/RowVersion并发控制类型在非Microsoft SQL Server数据库中的实现。
先上网搜索解决方案,找到Ak.Ini的博文http://www.cnblogs.com/akini/archive/2013/01/30/2882767.html,于是尝试使用文中介绍的方法。
项目中有一个类要解决并发更新的问题,该类定义:
public class Stock
{
public int Id { get; set; } [Required(ErrorMessageResourceName = "Generic_Required", ErrorMessageResourceType = typeof(ValidationMessage))]
public Location Location { get; set; } [Required(ErrorMessageResourceName = "Generic_Required", ErrorMessageResourceType = typeof(ValidationMessage))]
public Part Part { get; set; } public Batch Batch { get; set; } [Required(ErrorMessageResourceName = "Generic_Required", ErrorMessageResourceType = typeof(ValidationMessage))]
public int Quantity { get; set; } [Required(ErrorMessageResourceName = "Generic_Required", ErrorMessageResourceType = typeof(ValidationMessage))]
public int UpdatedBy { get; set; } [Required(ErrorMessageResourceName = "Generic_Required", ErrorMessageResourceType = typeof(ValidationMessage))]
public DateTime UpdatedTime { get; set; } public DateTime RowVersion { get; set; }
}
其中最后一个属性是用作并发控制的,MySqlMigrationSqlGenerator不允许byte[]类型上标记TimeStamp/RowVersion,这里使用DateTime类型。
这是EF生成的Stocks表定义:
> DESC kit.Stocks + ---------- + --------- + --------- + -------- + ------------ + ---------- +
| Field | Type | Null | Key | Default | Extra |
+ ---------- + --------- + --------- + -------- + ------------ + ---------- +
| Id | int(11) | NO | PRI | | auto_increment |
| Quantity | int(11) | NO | | | |
| UpdatedBy | int(11) | NO | | | |
| UpdatedTime | datetime | NO | | | |
| RowVersion | datetime | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| Location_Id | int(11) | NO | MUL | | |
| Part_PartNo | varchar(50) | NO | MUL | | |
| Batch_BatchNo | varchar(50) | YES | MUL | | |
+ ---------- + --------- + --------- + -------- + ------------ + ---------- +
8 rows
然后在DbContext的构造器中加入下面修改DbModelBuilder的代码:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); modelBuilder.Entity<Stock>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Stock>().Property(p => p.RowVersion).IsConcurrencyToken().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
上面代码中前两行是为了禁用EF级联删除的特性,可以参考我以前的博文:http://www.cnblogs.com/jlzhou/archive/2012/03/13/2394333.html
后两行显式声明Id属性为自增类型,其实EF默认会将Id属性设置为自增类型,但是在本例中,如果不显式声明,EF在生成数据库时会莫名其妙的将Id属性当作一般类型处理,不知道是不是因为最后一行设置RowVersion属性为Identity造成的。
我编写了一个小程序,用于显式控制EF根据类定义生成数据库,并且在生成数据库后,使用执行SQL语句的方式,修改数据库对象的定义,比如加入DEFAULT值或者添加索引等约束。下面是代码片段:
//DbContext构造器中的部分代码,通过isDoInitialize参数来控制是否初始化数据库。
public BestDbContext(string databaseName, bool isDoInitialize = true) : base(databaseName)
{
if (!isDoInitialize)
{
Database.SetInitializer<BestDbContext>(null);
}
} //初始化数据库
Database.SetInitializer(new DropCreateDatabaseAlways<BestDbContext>());
using (var db = new BestDbContext("name=" + databaseName))
{
try
{
db.Database.Initialize(force: false);
MessageBox.Show("Database initialized!");
}
catch (Exception ex)
{
MessageBox.Show("Initialization Failed... " + ex.Message);
}
string sql;
sql = @" ALTER TABLE `kit`.`Stocks` CHANGE COLUMN `RowVersion` `RowVersion` DATETIME NOT NULL
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ; ";
db.Database.ExecuteSqlCommand(sql);
}
注意上面代码最后的sql执行部分,这里加入对RowVersion数据库服务器端的缺省值设置,自MySQL 5.6.5版本开始,DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 选项也可以应用到Datetime类型的列。
最后验证上述方法,使用 Entity Framework Profiler 试用版(http://hibernatingrhinos.com/products/EFProf),下载解压缩后,在Project引用中加入对HibernatingRhinos.Profiler.Appender.dll的引用,然后在应用的启动代码部分Application_Start in web applications,Program.Main in windows / console applications or the App constructor for WPF applications),加入这一行代码:HibernatingRhinos.Profiler.Appender.EntityFramework.EntityFrameworkProfiler.Initialize();
启动应用程序调试,并且启动EFProf.exe监控程序,你就可以随时看到EF动态生成的SQL命令了,很是方便,唯一的遗憾是这个工具是收费购买的,微软又没有提供非MSSQL的数据库EF的SQL监控工具。
这是Stocks表在插入新记录时,EF生成的SQL语句:
INSERT INTO `Stocks`
(`Quantity`,
`UpdatedBy`,
`UpdatedTime`,
`Location_Id`,
`Part_PartNo`,
`Batch_BatchNo`)
VALUES ( 1,
1,
'2013-03-14T21:37:53' /* @gp1 */,
1,
'PART_A' /* @gp2 */,
NULL); SELECT `Id`,
`RowVersion`
FROM `Stocks`
WHERE row_count() > 0
AND `Id` = last_insert_id()
可以看出,保存新对象实例到数据库时,EF会从数据库取回RowVersion的值,而这个值是数据库那边生成的。
这是更新Stocks表时,EF生成的SQL语句:
UPDATE `Stocks`
SET `Quantity` = 6,
`UpdatedTime` = '2013-03-14T21:41:14' /* @gp1 */
WHERE (`Id` = 1)
AND (`RowVersion` = '2013-03-14T21:14:25' /* @gp2 */)
可以看出,在更新对象实例到数据库时,EF会从使用先前从数据库取回RowVersion的值和主键作为条件来更新数据行,从而实现乐观并发控制。
MySQL 实现 EF Code First TimeStamp/RowVersion 并发控制的更多相关文章
- Entity Framework Core 实现MySQL 的TimeStamp/RowVersion 并发控制
将通用的序列号生成器库 从SQL Server迁移到Mysql 遇到的一个问题,就是TimeStamp/RowVersion并发控制类型在非Microsoft SQL Server数据库中的实现.SQ ...
- Entity Framework 6 Code First 系列:无需修改实体和配置-在MySql中使用和SqlServer一致的并发控制
无需修改实体和配置,在MySql中使用和SqlServer一致的并发控制.修改RowVersion类型不可取,修改为Timestamp更不可行.Sql Server的RowVersion生成一串唯一的 ...
- 【Docker】 .Net Core 3.1 webapi 集成EF Code First,使用MySql进行业务操作 、配置swagger (三)
系列目录: [Docker] CentOS7 安装 Docker 及其使用方法 ( 一 ) [Docker] 使用Docker 在阿里云 Centos7 部署 MySQL 和 Redis (二) [D ...
- EF Code First 导航属性 与外键(转载)
EF Code First 导航属性 与外键 一对多关系 项目中最常用到的就是一对多关系了.Code First对一对多关系也有着很好的支持.很多情况下我们都不需要特意的去配置,Code First就 ...
- EF Code First学习系列
EF Model First在实际工作中基本用不到,前段时间学了一下,大概的了解一下.现在开始学习Code First这种方式.这也是在实际工作中用到最多的方式. 下面先给出一些目录: 1.什么是Co ...
- 1.什么是Code First(EF Code First 系列)
EF4.1中开始支持Code First .这种方式在领域设计模式中非常有用.使用Code First模式,你可以专注于领域设计,根据需要,为你一个领域的对象创建类集合,而不是首先来设计数据库,然后来 ...
- EF Code First Migrations数据库迁移
1.EF Code First创建数据库 新建控制台应用程序Portal,通过程序包管理器控制台添加EntityFramework. 在程序包管理器控制台中执行以下语句,安装EntityFramewo ...
- EF和MVC系列文章导航:EF Code First、DbContext、MVC
对于之前一直使用webForm服务器控件.手写ado.net操作数据库的同学,突然来了EF和MVC,好多新概念泉涌而出,的确犹如当头一棒不知所措.本系列文章可以帮助新手入门并熟练使用EF和MVC,有了 ...
- EF Code First 初体验
Code First 顾名思义就是先代码,再由代码生成数据库的开发方式. 废话不多说,直接来一发看看:在VS2010里新建一个空白解决方案,再依次添加两个类库项目:Model.DataAccess和一 ...
- 【极力分享】[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例【转载自https://segmentfault.com/a/1190000004152660】
[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例 本文我们来学习一下在Entity Framework中使用Cont ...
随机推荐
- Flyway简单迁移失败问题
因为我是初学者,所以问题 只是一些细节性问题,现在看看V开头创建数据库迁移时的错误 问题一: flyway 命名规则问题这个绝对的细节中的细节问题 问题一解决方案: 命名规则:一定要遵循flyway的 ...
- Linux之kill命令
1.kill命令的使用格式 kill [参数] [进程号] 2.kill命令的功能 发送指定的信号到相应进程.不指定型号将发送SIGTERM(15)终止指定进程.如果任然无法终止该程序可用" ...
- Dump Rtmp Stream To FLV File (从Rtmp流保存为FLV文件)
一.准备工作 搭建本地rtmp服务: https://www.cnblogs.com/doudouyoutang/p/6602430.html 获取使用到的库,openssl 和 librtmp 参考 ...
- k8s——statefulset
statefulset基础模版 [root@master statefulset]# cat web.yaml --- apiVersion: v1 kind: Service metadata: n ...
- k8s——核心概念篇
服务的分类 有状态 代表应用 nginx apache 优点 对客户端透明,无依赖关系,可以高效实现扩容,迁移 缺点 不能存储数据,需要额外的数据服务支撑 无状态 代表应用 MYSQL Redis 优 ...
- c# 语音识别 | 智能对话
在.NET4.0中,我可以借助System.Speech组件让电脑来识别我们的声音. 以上,当我说"name",显示"Darren",我说"age&q ...
- BOM弹窗 滚动条
// window.alert('弹出内容') 警告框 // window.prompt('弹出内容') 输入框 // 以 字符串 形式 存储输入 ...
- P9174
problem & blog 子任务 \(1\) 和子任务 \(2\) 都比较好做.所以我们这里不讲. 状态将是数字 \(n\) (每个颜色的频率的排序数组)的所有分区,因为当我们旋转每种颜色 ...
- windows 右键菜单编辑/删除
windows 右键菜单编辑/删除.WIN7,WIN8,WIN10,WIN11. 在 https://www.sordum.org/7615/easy-context-menu-v1-6/ 页面底部下 ...
- 什么Java注释
定义:用于解释说明程序的文字分类: 单行注释:格式: // 注释文字多行注释:格式: /* 注释文字 */ 文档注释:格式:/** 注释文字 */ 作用:在程序中,尤其是复杂的程序中,适当地加入注释可 ...