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 ...
随机推荐
- Chart.js (v2.9.4) 2-主要的函数和对象介绍
Color() :主要负责渲染图表时候,针对颜色处理相关函数 helpers_core:工具对象,提供了基础的工具函数功能,遍历数组,扩展对象,合并对象,克隆对象等等. core_defaults:负 ...
- C#复杂类型转为QueryString
使用 visual studio 创建 webapi 项目,并添加 DefaultController.cs,代码如下 public class DefaultController : ApiCont ...
- 7.18考试总结(NOIP模拟19)[u·v·w]
我们不是狼,我们只是长着獠牙的羊...... 前言 我真 TM 爱死 \(\frac{1}{4}\) 了. 老实说,这套题是真恶心,第一题还有一点思路,到了后面是一点都搞不定了. 总的来说,主要原因是 ...
- kubernetes的搭建(一)
集群的搭建 集群的类型 kubunetes的集群类型大致上分为两类: 一主多从和多主多从. 一主多从: 一台master节点和多台node节点,搭建简单,但是有单机故障的风险,适用于测试环境 多主多从 ...
- 算法学习笔记(15): Trie(字典树)
Trie树 Trie(字典树)是一种用于实现字符串检索的多叉树. Trie的每一个节点都可以通过 c 转移到下一层的一个节点. 我们可以看作可以通过某个字符转移到下一个字符串状态,直到转移到最终态为止 ...
- 【Java面试题-基础知识01】Java数据类型四连问?
一.Java中的基础数据类型有哪些? Java中的基本数据类型包括: 1. byte:8位有符号整数,范围为-128到127.2. short:16位有符号整数,范围为-32768到32767.3. ...
- Windows下cmd命令行ssh连接Linux服务器
1.window+R键进入运行 2.输入cmd,运行命令行工具 3.使用,命令ssh连接服务器 ssh -t 用户名@ip地址 -p 22 例如: 输入密码,显示连接成功
- runliuv MSDN I TELL YOU
runliuv MSDN I TELL YOU 老站点:WIN SEVER ,VISUAL STUDIO 早期版本 老站点:https://msdn.itellyou.cn/ 新站点:最近的WIN10 ...
- C# .NET MVC 表单提交前校验数据等
页面上写2个button,一个普通button,另一个是submit,submit的这个隐藏.校验函数写在普通button里,普通button click函数中去提交表单. 页面: <input ...
- EF,lambda 反向模糊查询
SELECT * FROM table as t WHERE "张三的偶像" LIKE t.userName; bool thisMchBelong = _mch_blackSer ...