[C#.NET][Entity Framework] 使用 MetadataType 改變 EF 預設檢查行為 - Code first from database

[C#.NET][Entity Framework] 使用 MetadataType 改變 EF 預設檢查行為 - Code first from database

資料庫的定義如下:

Name 是必填欄位,且有預設值空字串

image

小章廢言:

資料庫是儲存狀態的一個地方,保持狀態的可靠性,對系統而言是很重要的一件事,一但髒資料進到資料庫裡面,未來得花更大的力氣處理,債早晚都是要還的,別因小失大;資料庫要保存什麼狀態則是由功能需求決定,由功能需求的角度來看,便可決定欄位是否為必填,個人認為,應有兩種必填類型,一種是系統必填,另一種是使用者必填。

系統必填:經某種演算後填入或是初始化狀態
使用者必填:經由使用者在表單上填寫

不論是什麼必填類型,給予空字串,彷彿是在告訴大家說『這個欄位很重要,但裡面沒有東西』;神偷開了一個國王戒備森嚴的保險箱,但裡面卻空空如也。

語意不清楚會造成日後維護的困擾,應用程式本身應有自己的資料檢查機制,不應該廢了資料庫的檢查機制

開始進入主題:

這裡我用的是Code first form database,詳細作法請參考 http://www.dotblogs.com.tw/yc421206/archive/2014/03/18/144430.aspx

EF 工具幫我產生了 Account 類別,對應到資料庫的 Account Table,Name 屬性則是對應到資料庫的 Name 欄位;Name 屬性有兩個 Attribute,它們是用來檢查資料格式用的:

Required:必填
StringLength(50):字串長度 50

public partial class Account
{
    private string _name;

    public int Id { get; set; }

    [Required]
    [StringLength(50)]
    public string Name { get; set; }
}

 

有了 Entity Framework 不需要花費精神檢查資料,若預設的檢查方式不如你所預期,要擴充也是相當簡單,本篇不會描述如何擴充

測試程式碼如下:

public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        DemoDbContext db = new DemoDbContext();
        var account = new Account();
        db.Accounts.Add(account);

        try
        {
            db.SaveChanges();
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}

 

這樣寫 EF 就會賞你個錯誤

image

 

如何解決:

  1. 要解決這個問題,就是乖乖的填寫 Name,但我這邊的需求是要填一筆空字串,這表示我要繞過 EF 的檢查。
  2. 由於我們的類別是由 EF Tool 所產生的,不應該去動到EF Tool 所產生出來的檔案。因為 EF Tool 所產生的是 partial class,所以我們可以利用這個特性擴充我們所需要的功能,利用 MetadataType + partial class,修改EF的檢查機制,讓測試程式碼成功插入一筆垃圾資料
  3. 將 Require.AllowEmptyString=true,並再建構函數設定 Name 為空字串
public class AccountMetaData
{
    [Required(AllowEmptyStrings = true)]
    public string Name { get; set; }
}

[MetadataType(typeof(AccountMetaData))]
public partial class Account
{
    public Account()
    {
        this.Name = "";
    }
}

如此一來,便繞過 EF 的檢查..

套用資料庫設定的預設值

如 CreateDate 已經在資料庫設定 getdate(),你想要讓應用程式吃這個設定

image

 

由於在 C# 的 DateTime 預設值是 0001/01/01 ,所以 EF 所產生的 SQL 語法也會是那個日期,若要套用 SQL 的預設值可以使用 DatabaseGeneratedOption.Computed,EF 會罷工,不產生這個欄位的 T-SQL 語法

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


本文出自:http://www.dotblogs.com.tw/yc421206/archive/2015/04/12/151024.aspx

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo