.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N151216601
出刊日期:2015/12/02
開發工具:Visual Studio 2015 Enterprise
資料庫:SQL Server Express 2014
版本:.NET Framework 4.6、Entity Framework 6.1.3
Entity Framework Code First允許你使用自己的網域類別(Domain Class)當作Entity Framework的實體(Entity)類別來進行資料的查詢、更新或異動追蹤功能。Entity Framework Code First遵循一個設計模式,預設認定你的網域類別(Domain Class)遵照一些慣例進行設計。假若你的類別並未遵照這些慣例來進行設計,那麼Entity Framework允許你透過組態設定(Configuration)來修改預設的行為。
Entity Framework Code First開放兩種方式來讓你為類別加入組態設定:
- DataAnnotations(資料註解):使用Attribute語法設定。
- 使用Fluent API:使用程式碼設定。
本系列文章分為三篇,主要介紹使用Entity Framework Code First Data Annotations(資料註解)來客製化資料庫結構描述資訊。
在本篇文章之中,我們將介紹DataAnnotations的使用,透過System.ComponentModel.DataAnnotations 命名空間中的類別,來組態設定Entity Framework網域類別(Domain Class),以改寫預設的設計慣例。
預設Code First會為Entity類別中每一個可讀寫屬性(含getter與setter),定義一個對應的資料表欄位(Field)。若是定義成唯讀,或唯寫屬性,則不建立對應的資料表欄位。此外若宣告為欄位(Field),也不會建立對應的資料表欄位。
參考以下範例程式碼,Opera類別中包含一個OperaID屬性,預設Entity Framework Code First會把屬性名稱為ID或「類別名稱+ID」(英文大小寫都可以)的屬性,對應到資料庫資料表的主鍵欄位(Primary Key),若設為Primary Key的屬性是數值型別,也會將此屬性對應的資料表欄位設定為自動編號欄位。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFDemo {
class Program {
static void Main( string [ ] args ) {
OperaContext context = new OperaContext();
Console.WriteLine( context.Operas.Count() );
Console.WriteLine( "完成!" );
Console.ReadLine();
}
}
public class OperaContext: DbContext {
public OperaContext( ) {
Database.SetInitializer( new OperaInitializer() );
}
public DbSet<Opera> Operas { get; set; }
}
class OperaInitializer: DropCreateDatabaseAlways<OperaContext> {
protected override void Seed( OperaContext context ) {
var operas = new List<Opera>{
new Opera {
Title = "Cosi Fan Tutte",
Year = 1790,
Composer = "Mozart"
},
new Opera() {
Title = "Carmen",
Year = 1875,
Composer = "Bizet"
}
};
operas.ForEach( s => context.Operas.Add( s ) );
context.SaveChanges();
}
}
public class Opera {
public int ID { get; set; }
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
}
這個範例產生的資料表結構描述,請參考下圖所示:
圖 1
若將屬性命名為「ID」,例如下列程式碼所示,則此屬性對應的資料表欄位就會變成資料表主鍵(Primary Key):
public class Opera {
public int ID { get; set; }
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
這個範例產生的資料表結構描述,和上個例子一樣,得到相同的執行結果,請參考下圖所示:
圖 2
若類別的主鍵屬性命名方式不遵守此原則,則建立資料庫結構描述資訊時,就會產生例外錯誤,表示你必需為資料表指定主鍵資訊,才可以建立資料表。若主鍵屬性的命名方式不同,那麼你可以使用Key Attribute來變更這個行為。
Key Attribute
Key Attribute可以套用在網域類別(Domain Class)的屬性上,覆寫Entity Framework預設的主鍵屬性的命名慣例。以下範例程式碼在Opera 類別的OperaKey屬性上方套用Key Attribute,以表明其對應到資料表主鍵欄位(Primary Key):
public class Opera {
[Key]
public int OperaKey { get; set; }
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
這個範例產生的資料表結構描述,請參考下圖所示:
圖 3
OperaKey屬性將會對應到資料表的主鍵欄位(Primary Key),並且此欄位的「Identity Specification」設定為「true」,表示它是自動編號欄位,請參考下圖所示:
圖 4
若設為Primary Key的主鍵屬性不是數值型別,Code First便不會將此欄位設定為自動編號欄位,例如以下範例程式碼,OperaKey主鍵屬性的型別是字串型別:
public class Opera {
[Key]
public string OperaKey { get; set; }
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
這個範例產生的資料表結構描述,請參考下圖所示,OperaKey欄位的型別預設是「nvarchar(128)」,且「Identity Specification」的值設定為「false」:
圖 5
Entity類別中包含的欄位(Field)不能設定為Key欄位,例如以下程式碼,Opera類別中定義了OperaID欄位,Code First將無法建立主鍵欄位:
public class Opera {
public int OperaID;
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
複合主鍵(Composite keys)
若資料表的主鍵是由多個欄位組合而成,則利用Code First定義Entity 類別時,你可以在類別的多個屬性上方套用Key Attribute,並設定Column屬性,利用「Order」來決定主鍵的欄位組成順序,例如以下範例程式碼:
public class Opera {
[Key, Column( Order = 2 )]
public int OperaKey { get; set; }
[Key, Column( Order = 1 )]
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
這個範例產生的資料表結構描述,請參考下圖所示,主鍵的欄位由Title和OperaKey兩個欄位組成:
圖 6
Order屬性的索引可以是0或正整數值,可以跳號,且不連續,例如以下程式碼,Title和OperaKey的Order屬性分別是 100與200:
public class Opera {
[Key, Column( Order = 200 )]
public int OperaKey { get; set; }
[Key, Column( Order = 100 )]
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
以下程式碼,Title和OperaKey的Order分別是 0與200,此例和上一個例子,都會得到相同的主鍵欄位:
public class Opera {
[Key, Column( Order = 200 )]
public int OperaKey { get; set; }
[Key, Column( Order = 0 )]
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
但要小心,若Order的索引數值設定為負數,例如以下程式碼將「Title」的值設定為「-100」:
public class Opera {
[Key, Column( Order = 200 )]
public int OperaKey { get; set; }
[Key, Column( Order = -100 )]
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
則此屬性雖然有套用Key Attribute,但EntityFramework Code First並不會將之視為主鍵的一部分,這個範例產生的資料表結構描述,請參考下圖所示:
圖 7
另外,還值得一提的是,若使用複合主鍵,則Entity Framework不會將數值型別的Primary Key的欄位,設定為自動編號欄位,例如以下範例程式碼,主鍵由數值型別的OperaKey,與字串型別的Title組成:
public class Opera {
[Key, Column( Order = 1 )]
public int OperaKey { get; set; }
[Key, Column( Order = 2 )]
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
這個範例產生的資料表結構描述,請參考下圖所示,OperaKey欄位的「Identity Specification」設定為「false」:
圖 8
Required Attribute
Required Attribute用來設定此屬性對應的資料表欄位不可以為Null(NOT NULL)。而ASP.NET MVC則將此Attribute拿來用於資料驗證的動作,檢驗此屬性的值不可以不給。
public class Opera {
public int Operaid { get; set; }
[Required]
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
這個範例產生的資料表結構描述,請參考下圖所示,Title欄位被設定為「NOT NULL」:
圖 9
MaxLength Attribute
MaxLength Attribute可以套用到網域類別的string型別,或陣列型別。Entity Framework Code First利用此Attribute來設定資料表欄位可接受的最大值。而ASP.NET MVC則將此Attribute拿來用於資料驗證的動作,輸入的資料不能超過此Attribute的限制。以下範例程式碼設定Title屬性的最大長度為「200」:
public class Opera {
public int OperaID { get; set; }
[MaxLength(200)]
public string Title { get; set; }
public int? Year { get; set; }
public string Composer { get; set; }
}
相較於Title欄位,沒有設定MaxLength Attribute的Composer欄位,其長度則設定為MAX,這個範例產生的資料表結構描述,請參考下圖所示:
圖 10
Entity Framework Code First也會自動檢查Title屬性資料的長度是否超過設定值,若超過設定值,則寫入資料到資料庫時,會產生例外錯誤。