[Entity Framework][Code First]TimeStamp/RowVersion

TimeStamp/RowVersion

前言

通常資料在update的時候,有兩個人同時間把同一筆資料查詢出來,接下來修改完後存改,如果沒有經過一些特別處理,容易發生一個已經修改完的資料被另一個人覆蓋掉的情形。  而使用Entity Framework可以很簡單的使用Timestamp解決這種平行處理的問題。   

註:Timestamp的欄位作用是,只要該筆的資料被異動過,則Timestamp會產生一筆新的值,藉由這種方式,來達到安全平行處理的方式。

 

Timestamp

Convention None
Data Annotation Timestamp
Fluent Entity<T>.Property(t => t.PropertyName).IsRowVersion()
[Timestamp]
public byte[] RwoVersion { get; set; }

只要在Domain Class加上一個有Timestamp attribute的Property,在資料庫就會產生一個對應data type 為 Timestamp的欄位

有了Timestamp欄位後,當使用Entity Framework更新資料時,所產生的Update Script會多一個RowVersion判斷條件。

exec sp_executesql N'UPDATE [dbo].[People]
SET [FirstName] = @0
WHERE (([SocialNumber] = @1) AND ([RowVersion] = @2))
SELECT [RwoVersion]
FROM [dbo].[People]
WHERE @@ROWCOUNT > 0 AND [SocialNumber] = @1',N'@0 nvarchar(max) ,@1 int,@2 binary(8)',@0=N'Bob',@1=88,@2=0x0000000000001774

用這種方式,就可以確保更新此筆資料的時候,資料是還沒有被異動過的。  若不幸在更新的時候已經被異動過了,則RowVersion的值會不一致,造成Update失敗的問題,此時Entity Framework會拋出DbUpdateConcurrencyException,防止造成資料覆蓋的問題。

備註:RowVersion 和 TimeStamp指的是同一種data type,SQL Server 通常使用TimeStamp命名,其他資料庫則是使用RowVersion命名。

 

Non-Timestamp

Convention None
Data Annotation ConcurrencyCheck
Fluent Entity<T>.Property(t=>t.PropertyName).IsConcurrencyToken()

有些資料庫如果沒有支援Timestamp,其實也是可以做到部分的平行處理功能。  使用ConcurrencyCheck指定某一個欄位,則Entity Framework產生的Update Script會包含蓋欄位的條件。  使用ConcurrencyCheck的欄位沒有Timestamp每次Update後數值都會不一樣的特性就是了。

如以下範例:

public class Person
{
    [Key]
    public int PersonId { get; set; }
    
    [ConcurrencyCheck]
    public int SocialNumber { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
    
    public DateTime CreatedDate { get; set; }
}

產生的Update Script如下

exec sp_executesql N'UPDATE [dbo].[People]
SET [FirstName] = @0
WHERE (([PersonId] = @1) AND ([SocialNumber] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 int',@0=N'Bob',@1=1,@2=1234

這樣就可以保證兩個人以後同時update的時候,改到SocialNumber造成資料覆蓋的問題,只是這個效果沒有Timestampe那麼好就對了,因為SocialNumber是沒辦法自動變成其他數值。  而如果同時Update時,不幸別人改到SocialNumber造成Update失敗,則一樣會拋出DbUpdateConcurrencyException。

 

 

一天一分享,身體好健康。

該追究的不是過去的原因,而是現在的目的。