EntityFramework Code-First 簡易教程(六)-------領域類配置之DataAnnotations

EF Code-First提供了一個能夠用在領域類或其屬性上的DataAnnotation特性集合,DataAnnotation特性會覆蓋默認的EF約定。html

DataAnnotation存在於兩個命名空間裏:sql

System.ComponentModel.DataAnnotationsSystem.ComponentModel.DataAnnotations.Schema數據庫

注意: DataAnnotations只提供了一部分的配置選項,所有的配置選項在Fluent API中。數組

 

System.ComponentModel.DataAnnotations 包含的特性:

Attribute 描述
Key 標記一個屬性,其將會在關係表中被映射成主鍵
Timestamp 標記一個屬性,其將會在數據庫中被映射成一個不爲null的tiamestamp(時間戳)列
ConcurrencyCheck 這個屬性容許你標記一個或多個屬性,被標記的屬性將會在用戶編輯或刪除entity的時候進行併發檢查
Required 強制約束,該屬性必須有數據,不能爲null(一樣適用MVC)
MinLength 確保數組或字符串長度達到最小長度
MaxLength 數據庫中列的長度的最大值
StringLength 在數據字段中指定字符容許的最大長度和最小長度

System.ComponentModel.DataAnnotations.Schema 包含的特性:

Attribute 描述
Table 指定被映射的類在數據庫生成的表名
Column 指定被映射的屬性在表中的列名和數據類型
Index 在指定列上建立索引(僅EF6.1以上版本支持)
ForeignKey 給導航屬性指定外鍵屬性
NotMapped 標記的屬性不會被映射到數據庫
DatabaseGenerated 指定的屬性將會映射成數據庫表中的計算列,因此這個屬性應是隻讀的。也能夠用在把屬性映射成標識列(自增加列)
InverseProperty 當兩個類之間包含多重關係的時候,默認約定會排列組合他們的導航屬性組合並一一建立外鍵,InverseProperty能夠標記實際的主外鍵關係,從而過濾掉因排列組合出來的無用外鍵
ComplexType 標記一個類爲複雜類型

 

下面咱們來詳細介紹各個特性:

一、Key:

Key特性應用在類的屬性上。Code-First默認約定將名稱是"Id"或者{類名}+"Id"的屬性建立爲一個主鍵列,Key特性覆寫了默認約定,咱們能夠把任何想要成爲的主鍵的屬性標記爲Key而無論它是什麼名稱。架構

代碼以下:併發

using System.ComponentModel.DataAnnotations;

public class Student
{
    public Student()
    { 
        
    }

    [Key]
    public int StudentKey { get; set; }
     
    public string StudentName { get; set; }
        
}

數據庫中,Students表中的StudentKey列被建立成了主鍵app

dataannotations key attribute

 

咱們也能夠用用Key特性和Column特性建立混合主鍵,以下代碼所示:ui

using System.ComponentModel.DataAnnotations;

public class Student
{
    public Student()
    { 
        
    }
    [Key]
    [Column(Order=1)]
    public int StudentKey1 { get; set; }
     
    [Key]
    [Column(Order=2)]
    public int StudentKey2 { get; set; }
     
    public string StudentName { get; set; }
        
}

根據上面的代碼,在Students表中,建立出了混合主鍵StudentKey1和StudentKey2spa

dataannotations key attribute

注意: 當Key特性應用在單整型類型的屬性上時,會將其建立爲一個標識列,而混合鍵不管它是否是整型類型,都不會建立標識列。Key特性除了無符號整型(unsinged integers),能夠應用在如string、datatime、decimal等任何數據類型上。 .net

 

二、TimeStamp:

TimeStamp特性只能用在數據類型爲byte array的屬性上,TimeStamp特性會在數據庫表中建立一個timestamp屬性的列,Code-First自動使用TimeStamp列進行併發檢查。

(關於併發檢查,能夠參考Gyoung的筆記:Entity Framework 併發處理

代碼以下:

using System.ComponentModel.DataAnnotations;

public class Student
{
    public Student()
    { 
        
    }

    public int StudentKey { get; set; }
     
    public string StudentName { get; set; }
        
    [TimeStamp]
    public byte[] RowVersion { get; set; }
}

再次強調,標記TimeStamp特性的屬性類型必須是byte數組。

dataannotations TimeStamp attribute

 這樣,在數據庫Students表中就把RowVersion列建立成了timestamp(時間戳)

 

三、ConcurrencyCheck:

當EF對錶執行update命令時,Code-First會把標記了ConcurrencyCheck特性的列中的值插入到SQL語句的「where」子句中來進行併發檢查。以下代碼:

using System.ComponentModel.DataAnnotations;

public class Student
{
    public Student()
    { 
        
    }

    public int StudentId { get; set; }
     
    [ConcurrencyCheck]
    public string StudentName { get; set; }
}

如上所示,StudentName屬性上標記了ConcurrencyCheck特性,因此Code-First會在update命令中把StudentName列包含進去以進行樂觀併發檢查(有關樂觀併發和悲觀併發,上面Gyoung的筆記有介紹,這裏就很少討論)。以下代碼所示:

exec sp_executesql N'UPDATE [dbo].[Students]
SET [StudentName] = @0
WHERE (([StudentId] = @1) AND ([StudentName] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'Steve',@1=1,@2=N'Bill'
go            
       

注意:TimeStamp特性只能用在single byte數組屬性上,然而ConcurrencyCheck特性能夠用在任何數量和任何數據類型的屬性上。

 

 

四、Required:

應用了Required特性的屬性,將會在數據庫表中建立一個不爲null的列,須要留意的是,Required也是MVC的驗證特性。

代碼以下:

using System.ComponentModel.DataAnnotations;
    
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
     
    [Required]
    public string StudentName { get; set; }
        
}

 

在數據庫中,StudentName列已經被建立成不爲空。

dataannotations required attribute

 

五、MaxLength & MinLength:

Maxlength特性用在String或array類型的屬性上,EF Code-First將會把列的大小設置成指定值。值得注意的是,Maxlength也是MVC的驗證特性。

代碼以下:

using System.ComponentModel.DataAnnotations;
    
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
     
    [MaxLength(50)]
    public string StudentName { get; set; }
        
}

由於StudentName屬性被指定了[Maxlength(50)]特性,因此在數據庫中StudentName列被建立成nvarchar(50)。

dataannotations maxlength attribute

Entity Framework也會驗證被標記了MaxLength特性的屬性的值,若是該值大於被標記的最大值,EF將會拋出EntityValidationError。

MinLength:

MinLength特性是EF的一個驗證特性,其在數據庫模式中不起做用。若是咱們對標記了MinLength特性的屬性賦值(string或者array),其長度小於指定的最小值,那麼EF仍然會拋出EntityValidationError。

MinLength特性能夠和MaxLength特性一塊兒使用,以下代碼所示:

using System.ComponentModel.DataAnnotations;
    
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
     
    [MaxLength(50),MinLength(2)]
    public string StudentName { get; set; }
        
}

 

 如上代碼所示,StudentName屬性取值指定了只能是2-50個字符長度之間。

 

六、StringLength:

StringLength應用在string類型的屬性上,EF Code-First將會用StringLength指定的長度設置列的大小。和Required以及Maxlength同樣,StringLength也是MVC的驗證特性。

看下面的代碼:

using System.ComponentModel.DataAnnotations;

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
     
    [StringLength(50)]
    public string StudentName { get; set; }
        
}
       

根據代碼中StudentName屬性的[StringLength(50)]特性,在數據庫中,將會建立一個nvarchar(50)的列,以下所示:

dataannotations maxlength attribute

同理,EF也將會驗證StringLength特性中的值,若是用戶輸入的值大於指定的長度,將會拋出EntityValidationError。

 

七、Table:

Table特性應用在類上,默認的Code-First約定將會建立一個和類名同名的表名,Table特性覆寫默認的約定,EF Code-First將會建立一個以Table特性裏指定的字符串爲名稱的表。

代碼以下:

using System.ComponentModel.DataAnnotations.Schema;

[Table("StudentMaster")]
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
     
    public string StudentName { get; set; }
        
}

如上所示,Student類上應用了Table["StudentMaster"]特性,因此Code-First會覆寫默認的約定,建立一個名稱爲StudentMaster的表名

dataannotations table attribute

咱們也能夠用Table特性爲表指定一個架構名,代碼以下所示:

using System.ComponentModel.DataAnnotations.Schema;

[Table("StudentMaster", Schema="Admin")]
public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
     
    public string StudentName { get; set; }
        
}

數據庫以下,Code-First將會在Admin架構下建立一個StudentMaster表

dataannotations table attribute

  

八、Column:

Column特性應用在類的屬性上,和Table特性同樣,若是不指定Column特性的值,將會默認建立和屬性同名的列,不然就會建立指定的值。

看以下代碼:

using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
     
    [Column("Name")]
    public string StudentName { get; set; }
        
}

如上所示,Column["Name"]特性應用在StudentName屬性上,因此Code-First將會建立一個以"Name"爲名的列來代替默認的"StudentName"列名。數據庫以下:

dataannotations column attribute

咱們也可使用Column特性爲列指定排序(order)和類型(type),代碼以下:

using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
     
    [Column("Name", Order=1, TypeName="varchar")]
    public string StudentName { get; set; }
        
}

上面的代碼在數據庫Students表中建立了一個屬性爲varchar,排序第一的列Name

dataannotations column attribute

 

九、ForeignKey:

ForeignKey特性應用在類的屬性上。默認的Code-First約定預料外鍵屬性名與主鍵屬性名匹配,以下代碼:

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    //Foreign key for Standard
    public int StandardId { get; set; }

    public Standard Standard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
   
    }
}

如上代碼所示,Student類包含了外鍵屬性StandardId,其又是Standard類的主鍵屬性,這樣,Code-First將會在Students表中建立一個StandardId外鍵列。

Entity Framework code-first example

ForeignKey特性覆寫了默認約定,咱們能夠把外鍵屬性列設置成不一樣名稱,代碼以下:

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    //Foreign key for Standard
    public int StandardRefId { get; set; }

    [ForeignKey("StandardRefId")]
    public Standard Standard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
   
}

如上代碼所示,Student類包含了StandardRefId外鍵屬性,咱們使用ForeignKey["StandardRefId"]特性指定在Standard導航屬性上,因此Code-First將會把StandardRefId做爲外鍵,生成數據庫以下所示:

Entity Framework code-first example

ForeignKey特性也能夠用在外鍵屬性上,只要指定好它的導航屬性,即Standard屬性,以下所示:

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    //Foreign key for Standard
    
    [ForeignKey("Standard")]
    public int StandardRefId { get; set; }

    public Standard Standard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
   
}

這段代碼和上面把ForeignKey特性定義在Standard屬性上的效果是同樣的,在數據庫生成的Students表都建立了StandardRefId外鍵列。

 

十、NotMapped:

NotMapped特性用在類的屬性上,默認Code-First約定會爲那些全部包含了getter和setter的屬性建立列,NotMapped能夠覆寫默認的約定,讓那些標記了NotMapped特性的屬性不會在數據庫裏建立列。代碼以下:

using System.ComponentModel.DataAnnotations;

public class Student
{
    public Student()
    { 
        
    }

    public int StudentId { get; set; }
     
    public string StudentName { get; set; }
        
    [NotMapped]
    public int Age { get; set; }
}

如上代碼所示,NotMapped特性應用在Age屬性上,因此Code-First不會在Students表中建立Age列。

dataannotations NotMapped attribute

Code-First也不會爲那些沒有getter和setter的屬性建立列,在下面代碼例子中,Code-First不會爲FirstName和Age建立列。

using System.ComponentModel.DataAnnotations;

public class Student
{
    public Student()
    { 
        
    }
    private int _age = 0;

    public int StudentId { get; set; }
     
    public string StudentName { get; set; }
    
    public string FirstName { get{ return StudentName;}  }
    public string Age { set{ _age = value;}  }
    
}

 

 

十一、InverseProperty:

咱們已經知道,若是類中沒有包含外鍵屬性,Code-First默認約定會建立一個{類名}_{主鍵}的外鍵列。當咱們類與類之間有多個關係的時候,就可使用InverseProperty特性。

代碼以下:

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    public Standard CurrentStandard { get; set; }
    public Standard PreviousStandard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> CurrentStudents { get; set; }
    public ICollection<Student> PreviousStudents { get; set; }
   
    }
 }

如上代碼所示,Student類包含了兩個Standard類的導航屬性,一樣的,Standard類包含了兩個Student類的集合導航屬性,Code-First將會爲這種關係建立4個列。以下所示:

inverseproperty example

InverseProperty覆寫了這種默認約定而且指定對齊屬性,下面的代碼在Standard類中使用InverseProperty特性修復這個問題。

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    public Standard CurrentStandard { get; set; }
    public Standard PreviousStandard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    [InverseProperty("CurrentStandard")]
    public ICollection<Student> CurrentStudents { get; set; }
        
    [InverseProperty("PreviousStandard")]
        public ICollection<Student> PreviousStudents { get; set; }
   
    }
 }

如上代碼所示,咱們在CurrentStudents和PreviousStudents屬性上應用了InverseProperty特性,而且指定哪一個Student類的引用屬性屬於它,因此如今,Code-First在Student表中僅僅會建立兩個外鍵了。以下圖所示:

inverseproperty example

固然,若是你想改外鍵名稱,咱們就給導航屬性加上ForeignKey特性,以下代碼所示:

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    public int CurrentStandardId { get; set; }
    public int PreviousStandardId { get; set; }

    [ForeignKey("CurrentStandardId")]
    public Standard CurrentStandard { get; set; }
        
    [ForeignKey("PreviousStandardId")]
    public Standard PreviousStandard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    [InverseProperty("CurrentStandard")]
    public ICollection<Student> CurrentStudents { get; set; }
        
    [InverseProperty("PreviousStandard")]
    public ICollection<Student> PreviousStudents { get; set; }
   
}

 

上面的代碼將會建立出下面的數據庫表和列,咱們能夠看出,外鍵的名稱已經改變了。

inverseproperty example

 

 

到此,DataAnnotation已經介紹完了,若是有什麼不明白,或者我沒講清楚的地方,請你們留言~若有錯誤,也但願大神指出,不甚感激!

 

 下篇開始,咱們開始講Fluent API,嗯,先睡了。。。

相關文章
相關標籤/搜索