mysql ef 随机排序_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 classStock

{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 voidOnModelCreating(DbModelBuilder modelBuilder)

{

modelBuilder.Conventions.Remove();

modelBuilder.Conventions.Remove();

modelBuilder.Entity().Property(p =>p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

modelBuilder.Entity().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(null);

}

}//初始化数据库

Database.SetInitializer(new DropCreateDatabaseAlways());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);

}stringsql;

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的值和主键作为条件来更新数据行,从而实现乐观并发控制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值