EFCodeFirst模式使用的是約定大於配置的編程模式,這種模式利用默認約定根據咱們的領域模型創建概念模型。而後咱們也能夠經過配置領域類來覆蓋默認約定。web
覆蓋默認約定主要用兩種手段:sql
1.數據註釋屬性(Data Annotations Attributes)數據庫
2.FluentAPI編程
咱們能夠給領域類或者類的屬性添加數據註釋屬性來實現覆蓋默認約定,其實在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類型,主要用於解決高併發問題app 注:一個類只能用一次,且修飾的屬性必須爲byte[]類型ide |
ConcurrencyCheck | 數據庫中對應列進行樂觀併發檢測,主要用於解決高併發問題 |
Required | 屬性不爲空,數據中對應列 |
MinLength/MaxLength | 屬性和數據庫中的最小/最大的string長度 |
StringLength | 屬性和數據庫中的最小,最大 |
架構屬性高併發
Table | 用於實體,配置實體對應的數據庫表名和表結構 |
Column | 用於屬性,配置屬性對應數據庫列名,順序和數據類型 |
Index | 用於屬性,配置對應數據庫的列爲索引 |
ForeignKey | 用於屬性,指定屬性爲一個外鍵 |
NotMapped | 用於實體/屬性,不在數據庫中生成映射 |
DataBaseGernerated | 用於屬性,設置數據庫對應列值的生成,如identity,computed或者none |
EF6中經過Key和Column屬性能夠實現複合主鍵,一個栗子:ui
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()方法來實現。
一個栗子:
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; } }
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用於任何數據類型的屬性且能在一個類中使用屢次。