mysql timestamp 并发_MySQL 实现 EF Code First TimeStamp/RowVersion 并发控制
在將項(xiàng)目遷移到MySQL 5.6.10數(shù)據(jù)庫(kù)上時(shí),遇到和遷移到PostgreSQL數(shù)據(jù)庫(kù)相同的一個(gè)問(wèn)題,就是TimeStamp/RowVersion并發(fā)控制類型在非Microsoft SQL Server數(shù)據(jù)庫(kù)中的實(shí)現(xiàn)。
先上網(wǎng)搜索解決方案,找到Ak.Ini的博文http://www.cnblogs.com/akini/archive/2013/01/30/2882767.html,于是嘗試使用文中介紹的方法。
項(xiàng)目中有一個(gè)類要解決并發(fā)更新的問(wèn)題,該類定義:
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; }
}
其中最后一個(gè)屬性是用作并發(fā)控制的,MySqlMigrationSqlGenerator不允許byte[]類型上標(biāo)記TimeStamp/RowVersion,這里使用DateTime類型。
這是EF生成的Stocks表定義:
> DESCkit.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的構(gòu)造器中加入下面修改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級(jí)聯(lián)刪除的特性,可以參考我以前的博文:http://www.cnblogs.com/jlzhou/archive/2012/03/13/2394333.html
后兩行顯式聲明Id屬性為自增類型,其實(shí)EF默認(rèn)會(huì)將Id屬性設(shè)置為自增類型,但是在本例中,如果不顯式聲明,EF在生成數(shù)據(jù)庫(kù)時(shí)會(huì)莫名其妙的將Id屬性當(dāng)作一般類型處理,不知道是不是因?yàn)樽詈笠恍性O(shè)置RowVersion屬性為Identity造成的。
我編寫了一個(gè)小程序,用于顯式控制EF根據(jù)類定義生成數(shù)據(jù)庫(kù),并且在生成數(shù)據(jù)庫(kù)后,使用執(zhí)行SQL語(yǔ)句的方式,修改數(shù)據(jù)庫(kù)對(duì)象的定義,比如加入DEFAULT值或者添加索引等約束。下面是代碼片段:
//DbContext構(gòu)造器中的部分代碼,通過(guò)isDoInitialize參數(shù)來(lái)控制是否初始化數(shù)據(jù)庫(kù)。
public BestDbContext(string databaseName, bool isDoInitialize = true) : base(databaseName)
{if (!isDoInitialize)
{
Database.SetInitializer(null);
}
}//初始化數(shù)據(jù)庫(kù)
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執(zhí)行部分,這里加入對(duì)RowVersion數(shù)據(jù)庫(kù)服務(wù)器端的缺省值設(shè)置,自MySQL 5.6.5版本開始,DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 選項(xiàng)也可以應(yīng)用到Datetime類型的列。
最后驗(yàn)證上述方法,使用?Entity Framework Profiler 試用版(http://hibernatingrhinos.com/products/EFProf),下載解壓縮后,在Project引用中加入對(duì)HibernatingRhinos.Profiler.Appender.dll的引用,然后在應(yīng)用的啟動(dòng)代碼部分Application_Start in web applications,Program.Main in windows / console applications or the App constructor for WPF applications),加入這一行代碼:HibernatingRhinos.Profiler.Appender.EntityFramework.EntityFrameworkProfiler.Initialize();
啟動(dòng)應(yīng)用程序調(diào)試,并且啟動(dòng)EFProf.exe監(jiān)控程序,你就可以隨時(shí)看到EF動(dòng)態(tài)生成的SQL命令了,很是方便,唯一的遺憾是這個(gè)工具是收費(fèi)購(gòu)買的,微軟又沒(méi)有提供非MSSQL的數(shù)據(jù)庫(kù)EF的SQL監(jiān)控工具。
這是Stocks表在插入新記錄時(shí),EF生成的SQL語(yǔ)句:
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()
可以看出,保存新對(duì)象實(shí)例到數(shù)據(jù)庫(kù)時(shí),EF會(huì)從數(shù)據(jù)庫(kù)取回RowVersion的值,而這個(gè)值是數(shù)據(jù)庫(kù)那邊生成的。
這是更新Stocks表時(shí),EF生成的SQL語(yǔ)句:
UPDATE`Stocks`SET `Quantity` = 6,
`UpdatedTime`= '2013-03-14T21:41:14' /*@gp1*/
WHERE (`Id` = 1)AND (`RowVersion` = '2013-03-14T21:14:25' /*@gp2*/)
可以看出,在更新對(duì)象實(shí)例到數(shù)據(jù)庫(kù)時(shí),EF會(huì)從使用先前從數(shù)據(jù)庫(kù)取回RowVersion的值和主鍵作為條件來(lái)更新數(shù)據(jù)行,從而實(shí)現(xiàn)樂(lè)觀并發(fā)控制。
總結(jié)
以上是生活随笔為你收集整理的mysql timestamp 并发_MySQL 实现 EF Code First TimeStamp/RowVersion 并发控制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 二叉搜索时与双向链表python_剑指O
- 下一篇: mysql语句表名大小写敏感_Mysql