[Entity Framework][Code First]DatabaseGenerated

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直接做,可參考此文章

https://andy.mehalick.com/2014/02/06/ef6-adding-a-created-datetime-column-automatically-with-code-first-migrations/

 

小結

DatabaseGeneratedOption的設定就只有這三種,每種設定都有該情境可以使用,若不瞭解其中的為什麼設定的原因,都只依靠Convention產生出來的資料庫容易造成與預期不一樣的結果。

 

 

 

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

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