深入了解EntityFramework——数据注解属性
當慣例規則不符合設計需求時,我們可以使用數據注解配置打造更合適的數據庫模型。本文根據示例項目對常用的數據注解屬性做一個簡要的舉例說明。
EFCodeFirst使用的約定大于配置的的編程模式,?這種模式利用默認約定根據我們的領域模型建立概念模型。然我們可以用配置領域來覆蓋默認約定。覆蓋默認約定主要有兩種手段:
1、數據注解屬性。
2、FluentAPI。
| Key | 數據庫中對應為主鍵 |
| TimeStamp | 數據庫中對應類型為timestamp類型,主要用于解決高并發問題。注:一個類只能用一次,且修飾的屬性必須為byte[]類型 |
| ConcurrencyCheck | 數據庫中對應列為進行樂觀并發檢測,主要用于檢測高并發問題 |
| Required | 屬性不能為空,數據庫中對應列不能空 |
| MinLength/MaxLength | 屬性和數據庫中最大和最小String長度 |
?
| Schema | 配置實體對應的數據庫架構名 |
| Table | 配置實體類對應的表名 |
| Column | 用于配置實體類中的屬性,配置屬性對應的數據庫列名,順序和數據類型 |
| ForeignKey | 用于屬性,指定屬性為一個外鍵 |
| NotMapped | 用于實體或者屬性,不在數據庫中生成映射 |
| DataBaseGernerated | 用于屬性,設置數據庫對應列值的生成,如identity,computed或者none |
新建一個空的控制臺應用程序,名叫DADemo,如下圖所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?
選擇“空CodeFirst模型”建立所需的ADO.NET實體數據模型,如下圖所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?
增加Product.cs文件,代碼如下圖所示:
namespace DADemo {public class Product{public int Id { get; set; }public string Name { get; set; }public int Price { get; set; }public string Category { get; set; }} }在KTStoreModel.cs文件中增加如下代碼以支持對應的Product數據存取。?
public virtual DbSet<Product> Product { get; set; }在App.config中修改自動生成的連接字符串為指定字符串。
修改Product.cs中代碼為如下圖所示:
namespace DADemo {[Table("KProduct",Shema="MyProduct")]//數據庫名稱為MyProduct.KProductpublic class Product{[Key]//默認是將Id或者ClassNameId作為主鍵。通過[key]可以自定義主鍵,如果是數字類型,則自增public int PId { get; set; }[Required]//屬性不能為空[Column("ProductName")][MaxLength(50,ErrorMessage ="字段長度不得大于50"),MinLength(2)]//當程序中此字段保存時長度超過50時,程序會報錯public string Name { get; set; }[Column("ListPrice", Order=1,TypeName = "Money")]//映射到數據庫中的ListPrice列,并且對應類型是Money,列的順序是1,order從0開始public int Price { get; set; }[NotMapped]//數據庫中沒有對應的映射列public decimal SPrice { get; set; }[Index("CategoryIndex",IsUnique = true)]//索引名稱為CategoryIndex的唯一索引,直接使用[Index]時索引名詞IX_Category.[ForeignKey("CateId")]//指定外鍵屬性public string Category { get; set; }[Required]//屬性不能為空[DatabaseGenerated(DatabaseGeneratedOption.Computed)]public DateTime Created { get; set; }1741660888//在update操作時,包含在where子句中public byte[] RowVersion{get;set;}} }復合主鍵? ? ? ? ? ?
EF6中可以通過Key和Column實現復合主鍵,如下圖所示:
public class Student {[Key][Column(Order=1)]public int StudentKey { get; set; }[Key][Column(Order=2)]public int AdmissionNum { get; set; }public string StudentName { get; set; } }注意:EF Core中不支持通過【key】屬性來設置復合主鍵,可以通過FluentAPI的 hasKey() 方法來實現。?
? ? ?
ForeignKey?
Foreign注解用以強制指定外鍵復寫慣例原則,當我們需要自行指定作為外鍵的屬性時,可以通過ForeignKey的設置來達到目的。? ? ? ? ? ? ? ? ? ? ? ??
[Table("Order")] public partail class Order {//主鍵public int OrderId {get;set;}public DateTime OrderDate {get;set;}//導航屬性public virtual ICollection<OrderDetail> OrderDetails {get;set;} }[Table("OrderDetail")] public partial class OrderDetail {//主鍵public int Id {get;set;}public string ProductName {get;set;}public int Quantity{get;set;}public int Price{get;set;}//導航屬性public virtual Order MOrder {get;set;} }在實際的應用開發中過程中,通常會明確指定外鍵屬性,因此 鍵屬性必須呼符合慣例、數據注解或Fluent API規則。在慣例的原則下,CodeFirst根據導航屬性與鍵名稱的組合決定作為外鍵的屬性名稱,有以下3中規則:
1、 <導航屬性名稱><主體主鍵屬性名稱>
2、<主體類名稱><主鍵屬性名稱>
3、<主體主鍵屬性名稱>
?
根據第一個規則,OrderDetail外鍵的屬性是MOrderOrderId。
根據第二個規則,OrderDetail外鍵的屬性是OrderOrderId。
根據第三個規則,OrderDetail外鍵的屬性是OrderId。
?
如果不想用EF自動創建的外鍵,而是想把一個屬性設置成外鍵,有以下幾種方式:
1、[ForeignKey(導航屬性名)]? ?依賴實體(Student依賴Standard,所以Student是依賴實體)中在我們想設置為外鍵的屬性上指定導航屬性。如下圖所示:
[Table("OrderDetail")] public partial class OrderDetail {//主鍵public int Id {get;set;}public string ProductName {get;set;}public int Quantity{get;set;}public int Price{get;set;}[ForeignKey("Morder")]public int XOrder//導航屬性public virtual Order MOrder {get;set;} }2、[ForeignKey(屬性名)]?依賴實體中在導航屬性上指定屬性名。如下圖所示:
[Table("OrderDetail")] public partial class OrderDetail {//主鍵public int Id {get;set;}public string ProductName {get;set;}public int Quantity{get;set;}public int Price{get;set;}public int XOrderId;//導航屬性[ForeignKey("XOrderId")]public virtual Order MOrder {get;set;} }ConcurrencyCheck
首先說明一下悲觀并發和樂觀并發:
1、悲觀并發:比如有兩個用戶A,B同時登錄并修改文檔,如果A先修改則系統會把該文件鎖住。只有等A修改完并完全退出,B才能繼續修改。
2、樂觀并發:同上面的例子,A,B兩個用戶同時登錄,A先進入修改B也緊接著進入了。A修改文檔的同時B也在修改。如果A在保存之后,B再保存,此時系統檢測到數據庫文檔與B剛進入時候不一樣,B保存時會拋出異常,B修改失敗。
樂觀并發的基本出發點是:當保存數據的時候抱著一種樂觀的態度,不期望發生并發沖突,即使萬一發生并發沖突,也能捕捉到沖突異常,然后根據策略解決沖突,而解決沖突的方式一般分為Client wins(以后操作者為贏) 和 Store wins(以先存儲的數據為贏)。
ConcurrencyCheck屬性可以用在領域類的一個或多個屬性中,領域類的屬性使用它修飾后,數據庫中對應的列會啟用樂觀并發檢測。?示例代碼如下圖所示:
public class Student {public int StudentId { get; set; }[ConcurrencyCheck]public string StudentName { get; set; } }?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的深入了解EntityFramework——数据注解属性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux指令与数据库,Linux指令每
- 下一篇: 子网划分基础知识