升級 .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:
|
|
如下圖所示,當 <Nullable>enable</Nullable>
時,OptionalText 也會被加上 NOT NULL,換成 disable
才會恢復之前的規則。
所以,.NET 6 啟用 Nullable Context 時,Model 字串屬性要允許 null,型別也需改成 string?,這樣才會對應成 Nullable 資料庫欄位。(註:RequiredText 故意拿掉 = null! 觸發 CS8618 警告,證明有設 <Nullable>enable</Nullable>
)