mysql timestamp 并发_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表定義:
> 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的構造器中加入下面修改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的值和主鍵作為條件來更新數據行,從而實現樂觀并發控制。
總結
以上是生活随笔為你收集整理的mysql timestamp 并发_MySQL 实现 EF Code First TimeStamp/RowVersion 并发控制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二叉搜索时与双向链表python_剑指O
- 下一篇: mysql语句表名大小写敏感_Mysql