上午的時候把復雜類型學習了一下,想着趁着周六日把Code First學習完,所以下午還是把Code First中的關系學習下。在數據庫中最重要的恐怕就是E-R圖了,E-R體現了表與表直接的關系。使用Code First也需要把這種表與表直接的關系映射到數據庫中,所以關系映射在Code First中也是很重要的一節。Code First中主要包括一對一、一對多、多對多。
一、外鍵列名默認約定
Entity Framework Code First在根據默認約定創建外鍵時,外鍵列的名稱存在3種方式:目標類型的鍵名,目標類型名稱+目標類型鍵名稱,引用屬性名稱+目標類型鍵名稱。為了驗證這3種方式創建了兩個類:Province省份類、City城市類。
1.目標類型的鍵名
這種方式為要求在City表中外鍵列名與Province表中的主鍵列名相同,所以也就要求在City類中有定義與Province類中作為主鍵的屬性。如在Province類中主鍵屬性為ProvinceId,則需要在City類中也定義一個ProvinceId的屬性。
public class Province { [Key] public string ProvinceId { get; set; } public string ProvinceName { get; set; } public virtual ICollection<City> Citys { get; set; } }
public class City { public int CityId { get; set; } public string CityName { get; set; } public string ProvinceId { get; set; } }
還有一點就是看有的博客有的加virtual關鍵字,有的不加,這兩個的區別是什么呢?其實添加virtual關鍵字主要是為了懶加載,比如在獲取Province時,不加virtual則會把Citys也會獲取到,而加了virtual時只有在用到的時候才獲取。如果在City類的ProvinceId上加[Required]約定,則Province與City就會是級聯刪除的關系。
2.目標類型名稱+目標類型鍵名稱
這種的話就是在City表中映射成Province(類型名稱)+ProvinceId(類型鍵名稱)。這種只需在上面的基礎上稍作修改就是。即把City類中的ProvinceId屬性去掉。
public class City { public int CityId { get; set; } public string CityName { get; set; } }
3.引用屬性名稱+目標類型鍵名稱
這種方式為要求在City表中外鍵列名為在City類中引用Province的屬性名稱 + Province類的主鍵名稱。如:在City類中定義一個Province屬性Pro,則生成的外鍵名稱為Pro_ProvinceId。
public class City { public int CityId { get; set; } public string CityName { get; set; } [Required] public Province Pro { get; set; } }
上面也是加了[Required],也是構成了級聯刪除。
二、指定外鍵名
可以使用 [ForeignKey]約定來自定義外鍵名。
public class City { public int CityId { get; set; } public string CityName { get; set; } public string ProId { get; set; } [ForeignKey("ProId")]//ProId一對要存在 public Province Province { get; set; } }
三、一對多關系
上面的Province和City就屬於一對多的關系。
四、一對一
對於一對一的關系,首先它們要互相引用這是必須的。這還不夠,還是會報錯,需要設置誰參照誰,哪個是依賴類。
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFCodeFirstModels { public enum SexType { Male, Female } [Table("Person")] public class Person { [Key] public string PersonId { get; set; } //姓名 public string Name { get; set; } //性別 public SexType Sex { get; set; } //年齡 public int Age { get; set; } public virtual IDCard Card { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EFCodeFirstModels { public class IDCard { [Key,ForeignKey("Person")] public string PersonId { get; set; } //法定出生日期 public DateTime BirthDate { get; set; } public virtual Person Person { get; set; } } }
五、多對多
多對多關系用的最多的也舉例子最多的恐怕就是用戶和角色的關系了。一個用戶可以有多個角色,一個角色包含多個用戶。
public class User { public int UserId { get; set; } public string Name { get; set; } public virtual List<Role> Roles { get; set; } }
public class Role { public int RoleId { get; set; } public string Name { get; set; } public virtual List<User> Users { get; set; } }
通過導航屬性,Code First會默認生成一個中間表,來表示兩個的多對多關系。
Entity Framework Code First根據默認約定生成的多對多關聯關系的表時,默認啟用多對多的數據級聯刪除,可以添加代碼進行禁用。
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 禁用多對多關系表的級聯刪除 modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); }
六、對同一個實體多個引用的情況
首先看下下面的數據模型。
public class Person { public int PersonID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public List<Lodging> PrimaryContactFor { get; set; } public List<Lodging> SecondaryContactFor { get; set; } }
public class Lodging { public int LodgingId { get; set; } public string Name { get; set; } public string Owner { get; set; } public bool IsResort { get; set; } public decimal MilesFromNearestAirport { get; set; } //第一聯系人 public virtual Person PrimaryContact { get; set; } //第二聯系人 public virtual Person SecondaryContact { get; set; } }
Lodging(旅店)有兩個對Person表的引用,分別是PrimaryContact與SecondaryContact,同時,在Person表中也有對這兩個聯系人的導航:PrimaryContactFor與SecondaryContactFor。下面截圖是它的映射。
可以看到,Lodings表中一下子有4個外鍵,這也太多了,因為有兩套類型一樣的導航屬性與引用屬性,Code First無法確定它們之間的對應關系,就單獨為每個屬性都創建了一個關系。這肯定不是我們所期望的,為了讓Code First知道它們之間的對應關系,在這里要用到逆導航屬性來解決。使用InverseProperty約定。
public class Lodging { public int LodgingId { get; set; } public string Name { get; set; } public string Owner { get; set; } public bool IsResort { get; set; } public decimal MilesFromNearestAirport { get; set; } //第一聯系人 [InverseProperty("PrimaryContactFor")] public virtual Person PrimaryContact { get; set; } //第二聯系人 [InverseProperty("SecondaryContactFor")] public virtual Person SecondaryContact { get; set; } }