共用方式為


產生的值

資料庫數據行可以透過各種方式產生其值:主鍵數據行經常是自動遞增整數、其他數據行具有預設或計算值等等。此頁面詳細說明使用 EF Core 產生組態值的各種模式。

預設值

在關係資料庫上,可以使用預設值來設定數據行;如果插入數據列時沒有該數據行的值,則會使用預設值。

您可以在屬性上設定預設值:

modelBuilder.Entity<Blog>()
    .Property(b => b.Rating)
    .HasDefaultValue(3);

您也可以指定用來計算預設值的 SQL 片段:

modelBuilder.Entity<Blog>()
    .Property(b => b.Created)
    .HasDefaultValueSql("getdate()");

從 EF 10 開始,針對 SQL Server,您可以明確指定預設值條件約束的名稱,讓您更充分掌控資料庫架構。

modelBuilder.Entity<Blog>()
    .Property(b => b.Rating)
    .HasDefaultValue(3, "DF_Blog_IsActive");
modelBuilder.Entity<Blog>()
    .Property(b => b.Created)
    .HasDefaultValueSql("getdate()" , "DF_Blog_IsActive");

您也可以呼叫 UseNamedDefaultConstraints 來啟用所有預設條件約束的自動命名。 請注意,如果您有現有的移轉,則您新增的下一個移轉將會重新命名模型中的每一個默認條件約束。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.UseNamedDefaultConstraints();
}

計算資料行

在大部分關係資料庫上,數據行可以設定為在資料庫中計算其值,通常是參考其他數據行的表達式:

modelBuilder.Entity<Person>()
    .Property(p => p.DisplayName)
    .HasComputedColumnSql("[LastName] + ', ' + [FirstName]");

上述會建立 虛擬 計算數據行,其值會在每次從資料庫擷取時計算。 您也可以指定儲存計算資料 列(有時 稱為 持續性),這表示它會在資料列的每個更新上計算,並且會與一般數據行一起儲存在磁碟上:

modelBuilder.Entity<Person>()
    .Property(p => p.NameLength)
    .HasComputedColumnSql("LEN([LastName]) + LEN([FirstName])", stored: true);

主鍵

根據慣例,如果應用程式未提供值,則類型為 short、int、long 或 Guid 的非複合主鍵會設定為為插入實體產生值。 您的資料庫提供者通常會負責必要的設定;例如,SQL Server 中的數值主鍵會自動設定為 IDENTITY 資料行。

如需詳細資訊,請參閱有關密鑰的文件和特定繼承對應策略的指引。

明確配置值生成过程

我們上面看到,EF Core 會自動為主鍵設定值生成,但我們可能也希望對非鍵屬性進行相同的設定。 您可以設定任何屬性,使其針對插入的實體產生其值,如下所示:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime Inserted { get; set; }
}

同樣地,屬性可以設定為在新增或更新時產生其值:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime LastUpdated { get; set; }
}

不同於預設值或計算數據行,我們不會指定如何產生值;取決於所使用的資料庫提供者。 資料庫提供者可能會自動設定某些屬性類型的值產生,但其他提供者可能會要求您手動設定如何產生值。

例如,在 SQL Server 上,當 GUID 屬性設定為主鍵時,提供者會在用戶端自動使用演算法,生成最佳的循序 GUID 值。 不過,指定 ValueGeneratedOnAdd 在 DateTime 屬性上將不會有任何作用(請參閱下方章節了解 DateTime 值的生成)。

同樣地,設定為在新增或更新時產生的 byte[] 屬性,並標記為並行控制符的屬性,會以 rowversion 數據類型設置,以便在資料庫中自動產生值。 不過,指定 ValueGeneratedOnAdd 沒有任何作用。

請參閱提供者的文件,以了解其支援的具體值生成技術。 您可以 在這裡找到 SQL Server 值產生檔案。

產生日期/時間值

常見的要求是具有資料庫數據行,其中包含第一次插入數據列的日期/時間(新增時產生的值),或上次更新時(新增或更新時產生的值)。 由於有各種策略可以這麼做,EF Core 提供者通常不會針對日期/時間資料行自動設定值產生 - 您必須自行設定。

建立時間戳

將日期/時間數據行設定為具有數據列的建立時間戳,通常是使用適當的 SQL 函式設定預設值。 例如,在 SQL Server 上,您可以使用下列內容:

modelBuilder.Entity<Blog>()
    .Property(b => b.Created)
    .HasDefaultValueSql("getdate()");

請務必選取適當的函式,因為可能有數個函式存在(例如 GETDATE()GETUTCDATE())。

更新時間戳

雖然預存計算數據行似乎是管理上次更新時間戳的好解決方案,但資料庫通常不允許在計算數據行中指定這類 GETDATE() 函式。 或者,您可以設定資料庫觸發程式以達到相同的效果:

CREATE TRIGGER [dbo].[Blogs_UPDATE] ON [dbo].[Blogs]
    AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;

    IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;

    UPDATE B
    SET LastUpdated = GETDATE()
    FROM dbo.Blogs AS B
    INNER JOIN INSERTED AS I
        ON B.BlogId = I.BlogId
END

如需建立觸發程式的詳細資訊,請參閱在移轉中操作原始 SQL 的文件

覆蓋值生成

雖然屬性已設定為產生值,但在許多情況下,您仍可能會明確指定其值。 這是否實際運作取決於已設定的特定值產生機制:雖然您可以指定明確的值,而不是使用數據行的預設值,但計算數據行無法執行相同的作業。

若要使用明確的值覆蓋值生成,只需將屬性設定為任何不是該屬性類型的 CLR 預設值的值(例如,null 對於 string0 對於 intGuid.Empty 對於 Guid等)。

備註

嘗試將明確值插入 SQL Server IDENTITY 預設會失敗; 如需因應措施,請參閱這些檔

若要為被設定為在新增或更新時會產生值的屬性提供明確的值,您也必須如下設定屬性:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>().Property(b => b.LastUpdated)
        .ValueGeneratedOnAddOrUpdate()
        .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);
}

無值產生

除了上述案例等特定案例之外,屬性通常未設定任何值產生;這表示應用程式必須一律提供要儲存至資料庫的值。 此值必須先指派給新實體,才能新增至內容。

不過,在某些情況下,您可能會想停用根據慣例設定的值生成。 例如,int 類型的主鍵通常會隱含地設定為新增時自動產生值(例如,在 SQL Server 中為身份欄位)。 您可以透過下列方式停用此專案:

public class Blog
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int BlogId { get; set; }

    public string Url { get; set; }
}