EntityFramework系列:MySql的RowVersion
无需修改实体和配置,在MySql中使用和SqlServer一致的并发控制。修改RowVersion类型不可取,修改为Timestamp更不可行。Sql Server的RowVersion生成一串唯一的二进制保证Row的版本,无关TimeStamp,更无论TimeStamp的精度问题。使用MySql触发器只能解决uuid的插入的默认值和更新的随机值,由于MySql的自身为了防止无限递归的策略,它的触发器无法在当前表的触发器中更新当前表,所以触发器无法实现更新在SqlServer中由数据库生成的RowVersion字段的值。所以MySql中的RowVersion只能由应用程序赋值。
在EF中采用IsConcurrencyToken配置后RowVersion即自动用于where子句中用于比较Row Version,通过重写SaveChanges方法在每次添加和更新时设置RowVersion的值即可实现在更新时同时比较Row Version的当前版本和更新Row Version的目的,同时可以正确的取回更新后的Row Version值。
1.定义并发控制字段
public interface IRowVersion
{
byte[] RowVersion { get; set; }
}
2.配置并发控制字段
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.AddFromAssembly(typeof(MySqlDbContext).Assembly);
modelBuilder.Properties().Where(o => typeof(IRowVersion).IsAssignableFrom(o.DeclaringType)&&o.PropertyType==typeof(byte[])&&o.Name=="RowVersion")
.Configure(o => o.IsConcurrencyToken().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None));
Database.SetInitializer(new MySqlDbInitializer());
}
3.手动对RowVersion赋值
public override int SaveChanges()
{
this.ChangeTracker.DetectChanges();
var objectContext = ((IObjectContextAdapter)this).ObjectContext;
foreach (ObjectStateEntry entry in objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added))
{
var v = entry.Entity as IRowVersion;
if (v != null)
{
v.RowVersion = System.Text.Encoding.UTF8.GetBytes(Guid.NewGuid().ToString());
}
}
return base.SaveChanges();
}
4.检查生成的Sql语句
UPDATE `Customer` SET `PhoneNumber`=@gp1, `RowVersion`=@gp2 WHERE (`Id` = 1) AND (`RowVersion` = @gp3) -- @gp1: '635655975120384389' (Type = String, IsNullable = false, Size = 18) -- @gp2: 'System.Byte[]' (Type = Object, IsNullable = false, Size = 36) -- @gp3: 'System.Byte[]' (Type = Object, IsNullable = false, Size = 36)
5.查看数据中的RowVersion

6.准备测试代码
public static void Test()
{
var db1 = GetContext();
var customer1 = db1.Set<Customer>().FirstOrDefault();
customer1.PhoneNumber="t1";
using (var db2 = GetContext())
{
var customer2 = db2.Set<Customer>().FirstOrDefault();
customer2.PhoneNumber = "t2";
db2.SaveChanges();
}
db1.SaveChanges();
}
7.查看测试结果:

总结:
1.需要唯一版本号的生成支持,Sql Server(Compact)本身支持,MySql的uuid函数也支持。
2.需要设置Insert时的RowVersion默认值和更新RowVersion版本号,Sql Server(Compact)本身支持,MySql只支持不能用于RowVersion的TimeStamp的默认值和自动更新。因此在MySql中只能在应用中设置Row Version。
这个方案同时适用各种数据库,尤其是类似MySql和Sqlite这种不支持默认RowVersion字段的数据库。希望你不是找了好久才找到这个解决方案。
EntityFramework系列:MySql的RowVersion的更多相关文章
- 使用EntityFramework连接 Mysql
原文:使用EntityFramework连接 Mysql 1,安装VS.net 插件 http://forums.mysql.com/read.php?174,601041,601041 2,安装连接 ...
- MVC3、如何应用EntityFramework 连接MySql 数据库
原文:MVC3.如何应用EntityFramework 连接MySql 数据库 新的一年,新的开始. 今天总结的主题是在MySql中应用EntityFramework 的Code First模式. 开 ...
- EntityFramework For Mysql 动态切换数据源
1.简介 在工作中遇到一个问题.项目有三个数据库(三个数据库表结构一样),用户可以选择使用哪个数据库.其实就是动态切换数据库连接. 2.EntityFramework For Mysql 先来简单的介 ...
- MYSQL系列-Mysql存储引擎选择
MYSQL系列-Mysql存储引擎选择 //查看当前数据库支持的存储引擎 show engines \G; 创建表的时候可以通过engine=MyISAM指定存储引擎 MyISAM: .MYISAM不 ...
- mybatis&plus系列------Mysql的JSON字段的读取和转换
mybatis&plus系列------Mysql的JSON字段的读取和转换 一. 背景 在平常的开发中,我们可能会有这样的需求: 业务数据在存储的时候,并不是以mysql中的varchar丶 ...
- EntityFramework系列:SQLite的CodeFrist和RowVersion
没什么好说的,能支持DropCreateDatabaseIfModelChanges和RowVersion的Sqlite谁都想要.EntityFramework7正在添加对Sqlite的支持,虽然EF ...
- EntityFramework系列:Repository模式与单元测试
1.依赖IRepository接口而不是直接使用EntityFramework 使用IRepository不只是架构上解耦的需要,更重要的意义在于Service的单元测试,Repository模式本身 ...
- 使用ABP EntityFramework连接MySQL数据库
ASP.NET Boilerplate(简称ABP)是在.Net平台下一个很流行的DDD框架,该框架已经为我们提供了大量的函数,非常方便与搭建企业应用. 关于这个框架的介绍我就不多说,有兴趣的可以参见 ...
- (5.8)mysql高可用系列——MySQL中的GTID复制(实践篇)
一.基于GTID的异步复制(一主一从)无数据/少数据搭建 二.基于GTID的无损半同步复制(一主一从)(mysql5.7)基于大数据量的初始化 正文: [0]概念 [0.5]GTID 复制(mysql ...
随机推荐
- PhoneGap(二维码扫描 )
关于 phoneGap 如何做 二维码扫描 1. 先配置好, 环境 http://coenraets.org/blog/cordova-phonegap-3-tutorial/http: ...
- for循环三个表达式的执行时间
for(int i = 0; i < max; i++) { //代码 } 第一个表达式:声明一个变量i,初始值为0,表示当前的循环次数:循环刚开始时执行第二个表达式:循环条件,如果i的值小于m ...
- Android--Intent传递对象
Intent 传递对象通常有两种实现方式,Serializable 和 Parcelable: 一.Serializable:序列化,表示将一个对象转换成可存储或可传输的状态,序列化后的对象可以在网络 ...
- Android--Alarm机制
1.Alarm 能够实现 Android 中的定时任务,它与 Java 中的 Timer类的区别在于,Android 系统在休眠状态下时 Timer 类中的定时任务可能无法正常运行,而 Alarm 机 ...
- C语言-数据类型
数据类型 -基本数据类型 --char 字符型 --int 整型 --浮点型 ---float ---double -指针类型 --void* -空类型 -构架类型 --数组[] --结构体 str ...
- HTML5-表格
表格:表头<caption>,行<tr>,列<td>,标题<th> 属性:cellpadding="10" cellspacing= ...
- google搜索技巧汇总
由于不能访问google,可访问ggso.in进行搜索. 简单整理记录一下常用的一些Google搜索技巧:或操作一般搜索时,如果输入多个词,默认是与的关系,如输入词1和词2,即搜索同时包含词1和词2的 ...
- listview(3、动态刷新)
listview的动态刷新主要是调用adapter的notifyDataSetChanged. 在下面的例子中除了记录正常的刷新外,还记录一种错误的情况(注释掉的),作为备忘. notifyDataS ...
- Hdoop日记Day10---RPC机制
一.RPC(Remote Procedure Call)简介 RPC 是远程过程调用(Remote Procedure Call),即远程调用其他虚拟机中运行的javaobject.RPC 是一种客户 ...
- 一个老菜鸟所理解的UX及产品流
从事前端开发到目前为止已经有4年多的时间了,从一个小菜鸟一路依靠自学,到目前总算一个老菜鸟了.当然了,从事前端的工作,是免不了要对产品以及用户体验有些许了解的.最近谈论起这方面的内容,就按照自己的想法 ...