DatabaseGenerated
DatabaseGenerated Properites
Convention | Integer keys: Identity |
Data Annotation | DatabaseGenerated(DatabaseGeneratedOption) |
Fluent | Entity.Property(t=>t.PropertyName) .HasDatabaseGeneratedOption(DatabaseGeneratedOption) |
從Convention可以知道,只要是key值,且是int,則該欄位對應到資料庫的欄位設定就會是Identity(識別規格),而Identity功用就是該欄位不需要給值,該欄位值會自己遞增。
DatabaseGeneratedOption.Identity
但是某些情況,Convention並沒有設定為Identity,但是又必須要有這個功能,例如使用Guid。
public class Room
{
[Key]
public Guid Identifier { get; set; }
public string Name { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
使用Guid對應到資料庫的type是uniqueidentifier,而uniqueidentifier是沒有辦法設定Identity的,但是我們又希望Code First會自動幫我們自動產生一筆不會重複的Guid,此時就可以使用DatabaseGenerated來設定。
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Identifier { get; set; }
設定好後,可以看到insert的資料,自動幫你長出一筆不會重複Guid
這邊就有一個疑問了,uniqueidentifier明明就沒辦法設定Identity阿,可是為什麼能有Identity這樣的功能呢?
這讓我們track一下Entity Framework幫我們insert的過程就知道了:
exec sp_executesql N'DECLARE @generated_keys table([Identifier] uniqueidentifier)
INSERT [dbo].[Rooms]([Name], [StartDate], [EndDate])
OUTPUT inserted.[Identifier] INTO @generated_keys
VALUES (@0, @1, @2)
SELECT t.[Identifier]
FROM @generated_keys AS g JOIN [dbo].[Rooms] AS t ON g.[Identifier] = t.[Identifier]
WHERE @@ROWCOUNT > 0',N'@0 nvarchar(max) ,@1 datetime2(7),@2 datetime2(7)',@0=N'401',@1='2016-04-06 23:50:31.9131686',@2='2016-04-06 23:50:31.9131686'
看Insert指令就能知道,其實是Entity Framework在Insert的指令上面做了一些事情,所以才能達到Identity的功能。
備註:如果沒有設定DatabaseGeneratedOption.Identity,則預設的Guid都會是0,這種情形如果沒有手動給Guid的話,則會key duplication。
DatabaseGeneratedOption.None
另一種情況是,我的key值是int但是我不需望他有Identity的功能,例如:員工編號要自己決定
public class Person
{
[Key]
public int SocialNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
以此案例,預設的Convention會把SocialNumber設定為Identity,這樣會導致我自己無法決定SocialNumber的值會是什麼,所以這邊要設定為DatabaseGeneratedOption.None。
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int SocialNumber { get; set; }
DatabaseGeneratedOption.Computed
這是DatabaseGeneratedOption的最後一個設定,而Computed的功能,意旨是在說明這個欄位有預設值,且無法被Udpate,也無法被Insert,範例如下:
public class Person
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int SocialNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedDate { get; set; }
}
因為Entity Framework看到Computed的標記,所以在Insert或是Update的時候,產生的指令是不會包含該欄位的,所以要去資料庫設定CreatedDate預設值,否則CreatedDate會是null。
若不想從資料庫設定預設值,想從Code First直接做,可參考此文章
小結
DatabaseGeneratedOption的設定就只有這三種,每種設定都有該情境可以使用,若不瞭解其中的為什麼設定的原因,都只依靠Convention產生出來的資料庫容易造成與預期不一樣的結果。
一天一分享,身體好健康。
該追究的不是過去的原因,而是現在的目的。