0

EFCore 6.0 字串屬性對映欄位 NOT NULL 問題

 1 year ago
source link: https://blog.darkthread.net/blog/efcore-6-nullable/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

EFCore 6.0 字串屬性對映欄位 NOT NULL 問題-黑暗執行緒

升級 .NET 6 踩到的小問題。

依之前學到的 EF Core Model 設計,string 屬性預設對映的欄位預設為 Nullable,標註 [Required] 才會宣告為 NOT NULL。 不過,這條規則到 .NET 6 已有所改變。某段 EF Core 寫入資料庫時冒出欄位不允許 NULL,但 Model 中該屬性並未宣告為 [Required]。

研究發現這與 .NET 6 啟用 Nullable Context 有關,csproj 多了 <Nullable>enable</Nullable> 設定以支援 C# 8 推出的 Nullable Reference Type 概念。 設為 enable 時,Compiler 啟用 Null Reference Analysis 及相關語言特性,以字串為例,若 string 沒宣告成 string? 卻可能為 null 時會得到警告;若要明確標示此處就是要設成 null,可在後方加上 Null-Forgiving Operator, 例如 string x = null!;

若不想啟用此特性,設成 disable,Compiler 即會恢復 C# 7.3 以前的行為。

EF Core 產生資料庫對映 SQL Schema 時,也會受 Nullable Context 影響,當 <Nullable>enable</Nullable>,即使未加 [Required],Model 的字串屬性仍會被視為不可為 null,在 CREATE TABLE 時會加上 NOT NULL。

用以下程式重現問題。簡單宣告了 Entity 型別、DbContext,其中 RequiredText 有加註 [Required],另一個 OptionalText 則沒有,呼叫 DbContext.DataBase.GenerateCreateScript() 檢視其對映的 SQL Schema:

using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;

var options = 
    new DbContextOptionsBuilder<MyContext>()
    .UseSqlServer("data source=(localdb)\\mssqllocaldb")
    .Options;
var dbCtx = new MyContext(options);
Console.WriteLine(dbCtx.Database.GenerateCreateScript());

class MyContext : DbContext
{
    public DbSet<Item> Items { get; set; } = null!;
    public MyContext(DbContextOptions<MyContext> options)
        : base(options) { }
}
public class Item //Entity 型別
{
    //慣例,屬性名稱為 Id 或 <type name>Id 會自動成為 Entity 的 Key
    public int ItemId { get; set; }
    [Required] 
    public string RequiredText { get; set; } = null!;
    public string OptionalText { get; set; } = null!;
}

如下圖所示,當 <Nullable>enable</Nullable> 時,OptionalText 也會被加上 NOT NULL,換成 disable 才會恢復之前的規則。

Fig1_638035512109838065.png

所以,.NET 6 啟用 Nullable Context 時,Model 字串屬性要允許 null,型別也需改成 string?,這樣才會對映成 Nullable 資料庫欄位。(註:RequiredText 故意拿掉 = null! 觸發 CS8618 警告,證明有設 <Nullable>enable</Nullable>)

Fig2_638035512111765893.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK