KeyAttribute 數據庫設置主鍵。若是爲int類型,將自動設置爲自增加列。編程
系統默認以Id或類名+Id做爲主鍵。
StringLengthAttribute 數組可設置最大最小長度以及驗證提示信息等。最大長度會映射到數據庫。
MaxLengthAttribute 服務器最大長度。會映射的數據庫。
ConcurrencyCheckAttribute 架構修改或刪除時,將帶此屬性的列的原有值與主鍵一塊兒傳送到數據庫,若是傳遞的值與數據庫中不一致,則修改或刪除失敗。用於併發檢查。
RequiredAttribute 併發必填字段。將映射到數據庫,使字段屬性爲 not null。客戶段做必填項驗證。
TimestampAttribute app用於併發檢查,一個實體類中只能有一個標記爲此屬性。框架
[Timestamp] public Byte[] TimeStamp { get; set; }這樣,Code First 將在數據庫表中建立一個不可爲空的 Timestamp 列。less
指定列名
[Column(「BlogDescription", TypeName="ntext")]
public String Description {get;set;}
TableAttribute指定表名
[Table("InternalBlogs")]
public class Blog
InversePropertyAttribute兩個類之間存在多個關係時,將使用 InverseProperty。
ForeignKeyAttribute用於外鍵名稱與主鍵不一致的狀況。
DatabaseGeneratedAttributeIdentity 自增加列,通常主鍵會自動設置此屬性,非主鍵才須要設置。
None 用於不將主鍵設置爲自增加列。
Computed 不讓實體框架嘗試更新這些列,通常用於使用默認值。
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
不能添加[Required],驗證通不過。也沒必要添加[Required],數據庫中自動設置爲 not null。
bool => 0 (false)
int => 0
float => 0
decimal => 0
datetime => 1900-01-01 00:00:00
byte => 0 在數據庫中爲 tinyint (取值範圍0-255)
short=> 0 在數據庫中爲 smallyint
若是設置了
[DatabaseGenerated(DatabaseGenerationOption.Computed)] ,再取消,數據庫中也不會修改
除了string 外,基本都容許有默認值
數值類型也沒有必要在數據庫中添加默認值,值類型在初始化時,自動會賦予默認值並保存到數據庫中。
datetime 或 string 若是想使用默認值,能夠在構造函數中進行初始化。
不映射到數據庫,通常用於將映射到數據庫的字段經過計算獲取只讀值。
經過實體框架 Code First,可使用您本身的域類表示 EF 執行查詢、更改跟蹤和更新函數所依賴的模型。Code First 利用稱爲「約定先於配置」的編程模式。這就是說,Code First 將假定您的類聽從 EF 所使用的約定。在這種狀況下,EF 將可以找出本身工做所需的詳細信息。可是,若是您的類不遵照這些約定,則能夠向類中添加配置,以向 EF 提供它須要的信息。
Code First 爲您提供了兩種方法來向類中添加這些配置。一種方法是使用名爲 DataAnnotations 的簡單特性,另外一種方法是使用 Code First 的 Fluent API,該 API 向您提供了在代碼中以命令方式描述配置的方法。
本文重點介紹如何使用 DataAnnotations(在 System.ComponentModel.DataAnnotations 命名空間中)對類進行配置,着重講述經常使用的配置。不少 .NET 應用程序(如 ASP.NET MVC)都可以理解 DataAnnotations,它容許這些應用程序對客戶端驗證使用相同的註釋。
我將經過 Blog 和 Post 這兩個簡單的類來講明 Code First DataAnnotations。
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string BloggerName { get; set;}
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public ICollection<Comment> Comments { get; set; }
}
Blog 和 Post 類自己就遵照 Code First 約定,無需調整便可讓 EF 與之共同使用。但您也可使用註釋向 EF 提供有關類以及類所映射到的數據庫的更多信息。
實體框架依賴於每一個具備鍵值的實體,它使用鍵值來跟蹤實體。Code First 依賴的一個約定是它在每個 Code First 類中以何種方式表示哪個屬性是鍵。該約定是查找名爲「Id」或類名與「Id」組合在一塊兒(如「BlogId」)的屬性。該屬性將映射到數據庫中的主鍵列。
Blog 和 Post 類都遵照此約定。但若是它們不遵照呢?若是 Blog 使用名稱 PrimaryTrackingKey,甚至使用 foo 呢?若是 Code First 找不到符合此約定的屬性,它將引起異常,由於實體框架要求必需要有一個鍵屬性。您可使用鍵註釋來指定要將哪個屬性用做 EntityKey。
public class Blog
{
[Key]
public int PrimaryTrackingKey { get; set; }
public string Title { get; set; }
public string BloggerName { get; set;}
public virtual ICollection<Post> Posts { get; set; }
}
若是您在使用 Code First 的數據庫生成功能,則 Blog 表將具備名爲 PrimaryTrackingKey 的主鍵列,該列默認狀況下還定義爲 Identity。
Required 註釋告訴 EF 某一個特定屬性是必需的。
在 Title 屬性中添加 Required 將強制 EF(和 MVC)確保該屬性中包含數據。
[Required]
public string Title { get; set; }
MVC 應用程序無需添加其餘代碼或更改標記,就能執行客戶端驗證,甚至還能使用屬性和註釋名稱動態生成消息。
Required 特性還將使被映射的屬性不可爲空來影響生成的數據庫。請注意,Title 字段已經更改成「not null」。
使用 MaxLength 和 MinLength 特性,您能夠就像對 Required 那樣指定其餘屬性驗證。
下面是具備長度要求的 BloggerName。該示例也說明如何組合特性。
[MaxLength(10),MinLength(5)]
public string BloggerName { get; set; }
MaxLength 註釋將經過把屬性長度設置爲 10 來影響數據庫。
MVC 客戶端註釋和 EF 4.1 服務器端註釋都要執行此驗證,也會動態生成錯誤消息:「字段 BloggerName 必須是最大長度爲 10 的字符串或數組類型。」該消息有一點長。不少註釋都容許您使用 ErrorMessage 特性來指定錯誤消息。
[MaxLength(10, ErrorMessage="BloggerName 必須在 10 個字符如下"),MinLength(5)]
public string BloggerName { get; set; }
您也能夠在 Required 註釋中指定 ErrorMessage。
Code First 約定指示具備受支持數據類型的每一個屬性都要在數據庫中有表示。但在您的應用程序中並不老是如此。例如,您能夠在 Blog 類中使用一個屬性來基於 Title 和 BloggerName 字段建立代碼。該屬性能夠動態建立,無需存儲。您可使用 NotMapped 註釋來標記不映射到數據庫的全部屬性,以下面的 BlogCode 屬性。
[NotMapped]
public string BlogCode
{
get
{
return Title.Substring(0, 1) + ":" + BloggerName.Substring(0, 1);
}
}
跨一組類描述域實體,而後將這些類分層以描述一個完整實體的狀況並很多見。例如,您能夠向模型中添加一個名爲 BlogDetails 的類。
public class BlogDetails
{
public DateTime?DateCreated { get; set; }
[MaxLength(250)]
public string Description { get; set; }
}
請注意,BlogDetails 沒有任何鍵屬性類型。在域驅動的設計中,BlogDetails 稱爲值對象。實體框架將值對象稱爲複雜類型。複雜類型不能自行跟蹤。
可是 BlogDetails 做爲 Blog 類中的一個屬性,將做爲 Blog 對象的一部分被跟蹤。爲了讓 Code First 認識到這一點,您必須將 BlogDetails 類標記爲 ComplexType。
[ComplexType]
public class BlogDetails
{
public DateTime?DateCreated { get; set; }
[MaxLength(250)]
public string Description { get; set; }
}
如今,您能夠在 Blog 類中添加一個屬性來表示該博客的 BlogDetails。
public BlogDetails BlogDetail { get; set; }
在數據庫中,Blog 表將包含該博客的全部屬性,包括在其 BlogDetail 屬性中所含的屬性。默認狀況下,每一個屬性都將添加複雜類型名稱前綴 BlogDetail。
另外,有趣的是,雖然 DateCreated 屬性在類中定義爲不可爲空的 DateTime,但相關數據庫字段是可爲空的。若是想影響數據庫架構,則必須使用 Required 註釋。
ConcurrencyCheck 註釋可用於標記要在用戶編輯或刪除實體時用於在數據庫中進行併發檢查的一個或多個屬性。若是以前使用 EF 設計器,則這等同於將屬性的 ConcurrencyMode 設置爲 Fixed。
如今讓咱們將 ConcurrencyCheck 添加到 BloggerName 屬性,看看它如何工做。
[ConcurrencyCheck, MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
public string BloggerName { get; set; }
調用 SaveChanges 時,由於 BloggerName 字段上具備 ConcurrencyCheck 註釋,因此在更新中將使用該屬性的初始值。該命令將嘗試經過同時依據鍵值和 BloggerName 的初始值進行篩選來查找正確的行。下面是發送到數據庫的 UPDATE 命令的關鍵部分,在其中您能夠看到該命令將更新 PrimaryTrackingKey 爲 1 且 BloggerName 爲「Julie」(這是從數據庫中檢索到該博客時的初始值)的行。
where (([PrimaryTrackingKey] = @4) and ([BloggerName] = @5))
@4=1,@5=N'Julie'
若是在此期間有人更改了該博客的博主姓名,則此更新將失敗,並引起 DbUpdateConcurrencyException 而且須要處理該異常。
使用 rowversion 或 timestamp 字段來進行併發檢查更爲常見。可是比起使用 ConcurrencyCheck 註釋,只要屬性類型爲字節數組,則不如使用更爲具體的 TimeStamp 註釋。Code First 將 Timestamp 屬性與 ConcurrencyCheck 屬性同等對待,但它還將確保 Code First 生成的數據庫字段是不可爲空的。在一個指定類中,只能有一個 timestamp 屬性。
將如下屬性添加到 Blog 類:
[Timestamp]
public Byte[] TimeStamp { get; set; }
這樣,Code First 將在數據庫表中建立一個不可爲空的 Timestamp 列。
若是您讓 Code First 建立數據庫,則可能但願更改它建立的表和列的名稱。也能夠將 Code First 用於現有數據庫。可是域中的類和屬性的名稱並不老是與數據庫中表和列的名稱相匹配。
個人類名爲 Blog,按照約定,Code First 將假定此類映射到名爲 Blogs 的表。若是不是這樣,您能夠用 Table 特性指定該表的名稱。舉例來講,下面的註釋指定表名稱爲 InternalBlogs。
[Table("InternalBlogs")]
public class Blog
Column 註釋更適於用來指定被映射列的特性。您能夠規定名稱、數據類型甚至列出如今表中的順序。下面是 Column 特性的示例。
[Column(「BlogDescription", TypeName="ntext")]
public String Description {get;set;}
不要將列的 TypeName 特性與 DataType DataAnnotation 相混淆。DataType 是一個用於 UI 的註釋,Code First 會將它忽略。
下面是從新生成後的表。表名稱已更改成 InternalBlogs,複雜類型的 Description 列如今是 BlogDescription。由於該名稱在註釋中指定,Code First 不會使用以複雜類型名稱做爲列名開頭的約定。
一個重要的數據庫功能是可使用計算屬性。若是您將 Code First 類映射到包含計算列的表,則您可能不想讓實體框架嘗試更新這些列。可是在插入或更新數據後,您的確須要 EF 從數據庫中返回這些值。您可使用 DatabaseGenerated 註釋與 Computed 枚舉一塊兒在您的類中標註這些屬性。其餘枚舉爲 None 和 Identity。
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
public DateTime DateCreated { get; set; }
當 Code First 生成數據庫時,您能夠對 byte 或 timestamp 列使用生成的數據庫,不然您只應該在指向現有數據庫時使用,由於 Code First 將不能肯定計算列的公式。
您閱讀過以上內容,知道默認狀況下,整數鍵屬性將成爲數據庫中的標識鍵。這與將 DatabaseGenerated 設置爲 DatabaseGenerationOption.Identity 是同樣的。若是不但願它成爲標識鍵,則能夠將該值設置爲 DatabaseGenerationOption.None。
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
不能添加[Required],驗證通不過。也沒必要添加[Required],數據庫中自動設置爲 not null。
bool => 0 (false)
int => 0
float => 0
decimal => 0
datetime => 1900-01-01 00:00:00
byte => 0 在數據庫中爲 tinyint (取值範圍0-255)
short=> 0 在數據庫中爲 smallyint
若是設置了 [DatabaseGenerated(DatabaseGenerationOption.Computed)] ,再取消,數據庫中也不會修改
除了string 外,基本都容許有默認值
注意:此頁面提供有關使用數據註釋在 Code First 模型中設置關係的信息。有關 EF 中的關係的通常信息和如何使用關係來訪問和操做數據,請參閱 關係和導航屬性。
Code First 約定將在您的模型中處理最經常使用的關係,可是在某些狀況下它須要幫助。
在 Blog 類中更改鍵屬性的名稱形成它與 Post 的關係出現問題。
生成數據庫時,Code First 會在 Post 類中看到 BlogId 屬性並識別出該屬性,按照約定,它與類名加「Id」匹配,並做爲 Blog 類的外鍵。可是在此 Blog 類中沒有 BlogId 屬性。解決方法是,在 Post 中建立一個導航屬性,並使用 Foreign DataAnnotation 來幫助 Code First 瞭解如何在兩個類之間建立關係(那就是使用 Post.BlogId 屬性)以及如何在數據庫中指定約束。
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
[ForeignKey("BlogId")]
public Blog Blog { get; set; }
public ICollection<Comment> Comments { get; set; }
}
數據庫中的約束顯示 InternalBlogs.PrimaryTrackingKey 與 Posts.BlogId 之間的關係。
類之間存在多個關係時,將使用 InverseProperty。
在 Post 類中,您可能須要跟蹤是誰撰寫了博客文章以及誰編輯了它。下面是 Post 類的兩個新的導航屬性。
public Person CreatedBy { get; set; }
public Person UpdatedBy { get; set; }
您還須要在這些屬性引用的 Person 類中添加內容。Person 類具備返回到 Post 的導航屬性,一個屬性指向該用戶撰寫的全部文章,一個屬性指向該用戶更新的全部文章。
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public List<Post> PostsWritten { get; set; }
public List<Post> PostsUpdated { get; set; }
}
Code First 不能自行使這兩個類中的屬性匹配。Posts 的數據庫表應該有一個表示 CreatedBy 人員的外鍵,有一個表示 UpdatedBy 人員的外鍵,可是 Code First 將建立四個外鍵屬性:Person_Id、Person_Id一、CreatedBy_Id 和 UpdatedBy_Id。
要解決這些問題,您可使用 InverseProperty 註釋來指定這些屬性的匹配。
[InverseProperty("CreatedBy")]
public List<Post> PostsWritten { get; set; }
[InverseProperty("UpdatedBy")]
public List<Post> PostsUpdated { get; set; }
由於 Person 中的 PostsWritten 屬性知道這指的是 Post 類型,因此它將與 Post.CreatedBy 創建關係。一樣,PostsUpdated 也將與 Post.UpdatedBy 創建關係。Code First 不會建立額外的外鍵。
表內主外鍵