EF CodeFirst系列(3)--- 數據注釋屬性


EFCodeFirst模式使用的是約定大於配置的編程模式,這種模式利用默認約定根據我們的領域模型建立概念模型。然后我們也可以通過配置領域類來覆蓋默認約定。

覆蓋默認約定主要用兩種手段:

1.數據注釋屬性(Data Annotations Attributes)

2.FluentAPI

1.數據注釋屬性

我們可以給領域類或者類的屬性添加數據注釋屬性來實現覆蓋默認約定,其實在MVC webApi中也會經常用到數據注釋屬性。一個栗子

[Table("StudentInfo",Schema ="MySchool")]//數據庫名為MySchool.StudentInfo
public class Student
{
    public Student() { }
        
    [Key]//默認把Id或者classNameId作為主鍵。通過[key]可以指定主鍵,如果是數字類型,默認自增
    public int SID { get; set; }

    [Column("Name",Order=1,TypeName="ntext")]//必有項:列名為Name ;非必有項:順序為1,數據庫中類型為ntext(order是從0開始的)
    [MaxLength(20)]
    public string StudentName { get; set; }

   [NotMapped]//不映射到數據庫中
    public int? Age { get; set; }

  public string Phone{get{return "13545678901";}}//getter,setter有一個不存在,就不會映射到數據庫

[Index("IndexName",IsClustered =true ,IsUnique =true)]//索引名為IndexName,是聚集索引和唯一索引,直接使用[index]時索引名為IX_StudentNo,為非聚集索引   public string StudentNo{get;set;}
[Timestamp]
//在update操作時,包含在where子句中 public byte[] RowVersion{get;set;}   public int StdId { get; set; }    [ForeignKey("StdId")] public virtual Standard Standard { get; set; } }

 

一些常用的數據注釋屬性

Key 數據庫中對應列為主鍵
Timestamp

數據庫中對應列為timestamp類型,主要用於解決高並發問題

注:一個類只能用一次,且修飾的屬性必須為byte[]類型

ConcurrencyCheck 數據庫中對應列進行樂觀並發檢測,主要用於解決高並發問題
Required 屬性不為空,數據中對應列
MinLength/MaxLength 屬性和數據庫中的最小/最大的string長度
StringLength 屬性和數據庫中的最小,最大

架構屬性

Table 用於實體,配置實體對應的數據庫表名和表結構
Column 用於屬性,配置屬性對應數據庫列名,順序和數據類型
Index 用於屬性,配置對應數據庫的列為索引
ForeignKey 用於屬性,指定屬性為一個外鍵
NotMapped 用於實體/屬性,不在數據庫中生成映射
DataBaseGernerated 用於屬性,設置數據庫對應列值的生成,如identity,computed或者none

2.一些補充

1.復合主鍵

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]屬性來設置復合主鍵,我們可以通過Fluent API的HasKey()方法來實現

2.ForeignKey的三種形式

一個栗子:

public class 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 int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
}

在上邊的栗子中,沒有使用ForeignKey覆蓋默認的約定,那么安照默認約定執行:EF找到導航屬性Standard,找到Standard的主鍵為StandardId,正好Student類中有StandardId屬性,那么就把StandardId設為外鍵;如果Student類沒有StandardId呢?EF會創建一個外鍵<導航屬性名>_<導航屬性主鍵>,在本例中就是Standard_StandardId

我們不想使用EF自動創建的外鍵,而是想把一個屬性設置成外鍵,但是這個屬性和導航屬性的主鍵名不一致,我們應該怎么去實現呢?

1.[ForeignKey(導航屬性名)]   依賴實體(Student依賴Standard,所以Student是依賴實體)中在我們想設置為外鍵的屬性上指定導航屬性

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

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

2.[ForeignKey(導航屬性名)] 依賴實體中在導航屬性上指定屬性名

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

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

3.主實體中在導航屬性上指定屬性名(不推薦)

ublic class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    public int StandardRefId { get; set; }
    public Standard Standard { get; set; }
}

public class Standard
{
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    [ForeignKey("StandardRefId")]
    public ICollection<Student> Students { get; set; }
}

3.ConcurrencyCheck解決高並發

  ConcurrencyCheck屬性可以用在領域類的一個或多個屬性中,領域類的屬性使用它修飾后,數據庫中對應的列會啟用樂觀並發檢測。

一個栗子:

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

上邊栗子中StudentName使用ConcurrencyCheck注釋,EF會在Update時將StudentName添加到where子句中。

using(var context = new SchoolContext()) 
{
    var std = new Student()
    {
        StudentName = "Bill"
    };

    context.Students.Add(std);
    context.SaveChanges();

    std.StudentName = "Steve";
    context.SaveChanges();
}

在執行SaveChanges()方法時,執行的Sql命令如下:

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只能用於byte[]類型,且一個類中只能用一次,而ConcurrencyCheck用於任何數據類型的屬性且能在一個類中使用多次。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM