Entity?Framework配置關(guān)系
一、Has方法與With方法
如:A類必須包含B類一個不為null的實例,而B類可選擇時候包含A類一個實例。
A.HasRequired(a => a.B).WithOptional(b => b.A);
1、Has方法:
- HasOptional:前者(A)可以包含后者(B)一個實例或者為null
- HasRequired:前者必須包含后者一個不為null的實例
- HasMany:前者包含后者實例的集合
2、With方法:
- WithOptional:后者(B)可以包含前者(A)一個實例或者null
- WithRequired:后者必須包含前者一個不為null的實例
- WithMany:后者包含前者實例的集合
二、一對一關(guān)系:
兩個類中先都要配置相應(yīng)的引用屬性
1、DataAnnotations數(shù)據(jù)標(biāo)注的方式
用到ForeignKey外鍵標(biāo)注。
public class Person { public int PersonId { get; set; } public int SocialSecurityNumber { get; set; } public string FirstName { get; set; } public string LastName { get; set; } [Timestamp] public byte[] RowVersion { get; set; } public PersonPhoto Photo { get; set; } } public class PersonPhoto { [Key, ForeignKey("PhotoOf")] //注意:PersonPhoto表中的PersonId既是外鍵也必須是主鍵 public int PersonId { get; set; } public byte[] Photo { get; set; } public string Caption { get; set; } public Person PhotoOf { get; set; } }
2、Fluent API方式
(1)1:0..1關(guān)系
PersonPhoto必須屬于一個Person,但是Person不一定有PersonPhoto, 此種情況下Person是一定存在的,所以它是主從關(guān)系主的一方。
modelBuilder.Entity<Person>().HasOptional(t => t.Photo).WithRequired(t => t.PhotoOf); modelBuilder.Entity<PersonPhoto>().HasRequired(p => p.PhotoOf).WithOptional(p => p.Photo);
(2)1:1 關(guān)系
PersonPhoto必須屬于一個Person,Person也必須有PersonPhoto。
modelBuilder.Entity<Person>().HasRequired(p => p.Photo ).WithRequiredPrincipal(); modelBuilder.Entity<PersonPhoto>().HasRequired(t => t.PhotoOf).WithRequiredDependent(t => t.Photo);
此種情況下,兩個都一定存在,要確定主從關(guān)系,需要使用WithRequiredPrincipal或WithRequiredDependent。
- 如果你選擇 WithOptionalPrincipal(當(dāng)前實體為主體;目標(biāo)實體為依賴對象)PersonPhoto表中有一個外鍵,指向Person表的主鍵。
- 如果你選擇 WithOptionalDependen t則相反(當(dāng)前實體為依賴對象;目標(biāo)實體為主體)則代表Person表中有一個外鍵,指向PersonPhoto表的主鍵,
Person表可以沒有對應(yīng)的PersonPhoto表數(shù)據(jù),但是PersonPhoto表每一條數(shù)據(jù)都必須對應(yīng)一條Person表數(shù)據(jù)。意思就是人可以沒有照片,但是有的照片必須屬于某個人。
三、一對多關(guān)系:
1、DataAnnotations方式
一對多關(guān)系很多情況下我們都不需要特意的去配置,通過一些引用屬性、導(dǎo)航屬性等檢測到模型之間的關(guān)系,自動為我們生成外鍵。
public class Destination {//景點類 public int DestinationId { get; set; } public string Name { get; set; } public string Country { get; set; } public string Description { get; set; } public byte[] Photo { get; set; } public List Lodgings { 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 Destination Target { get; set; } }
Code First觀察到Lodging類中有一個對Destination的引用屬性,或者Destination中又有一個集合導(dǎo)航屬性Lodgings,因此推測出Destination與Lodging的關(guān)系是一對多關(guān)系.
所以在生成的數(shù)據(jù)庫中為自動為Lodging表生成外鍵:外鍵名:Target_DestinationId
2、更改外鍵的nullable屬性和外鍵的名字
默認(rèn)情況下,如果你的外鍵命名是規(guī)范的話,Code First自動會將該屬性設(shè)置為外鍵,不再自動創(chuàng)建一個外鍵。
規(guī)范命名是指符合:命名為如下的形式:(在這里目標(biāo)類型就是Destination)
- [目標(biāo)類型的主鍵名]:如:DestinationId
- [目標(biāo)類型名稱]+[目標(biāo)類型主鍵名稱]:如:DestinationDestinationId
- [導(dǎo)航屬性名稱]+[目標(biāo)類型主鍵名稱]:如:TargetDestinationId
如:DestinationId屬性自動作為主鍵。
public class Lodging { public int? DestinationId { get; set; } public Destination Destination { get; set; } }
當(dāng)然我們也可以自己在類中增加一個外鍵。
1、使用Data Annotations指定外鍵:
注意ForeignKey位置的不同,其后帶的參數(shù)也不同。
[ForeignKey("Target")] public int TarDestinationId { get; set; } public Destination Target { get; set; }
或
public int TarDestinationId { get; set; } [ForeignKey("TarDestinationId")] public Destination Target { get; set; }
2、用Fluent API指定外鍵:
如果實體類沒定義AccommodationId,那么可以使用Map方法直接指定外鍵名:.Map(s => s.MapKey("AccommodationId"))
(1)Lodging一定歸屬于一個Destination,這種關(guān)系是1:n。
modelBuilder.Entity<Destination>().HasMany(d => d.Lodgings).WithRequired(l => l.Destination).Map(l => l.MapKey("DestinationId")); modelBuilder.Entity<Lodgings>().HasRequired(l => l.Target).WithMany(d=>d.Lodgings).HasForeignKey(l => l.TarDestinationId);
(2)Post可以單獨存在,不用歸屬于Blog,這種關(guān)系是0..1:n。
modelBuilder.Entity<Destination>().HasMany(d => d.Lodgings).WithOptional(l => l.Destination).Map(l => l.MapKey("DestinationId")); modelBuilder.Entity<Lodgings>().HasOptional(l => l.Target).WithMany(d => d.Lodgings).HasForeignKey(l => l.TarDestinationId);
3、對同一實體多個引用的情況
public class Person { public int PersonID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public List PrimaryContactFor { get; set; } public List 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 Destination Target { get; set; } //第一聯(lián)系人 public Person PrimaryContact { get; set; } //第二聯(lián)系人 public Person SecondaryContact { get; set; } }
Lodging(旅店)有兩個對Person表的引用,分別是PrimaryContact與SecondaryContact,
同時,在Person表中也有對這兩個聯(lián)系人的導(dǎo)航:PrimaryContactFor與SecondaryContactFor。
因為在這兩個表之間存在多個一對多關(guān)系,所以Code First無法處理這種情況。
為了讓Code First知道它們之間的對應(yīng)關(guān)系,在這里要用到逆導(dǎo)航屬性來解決。
(1)使用Data Annotations:
//第一聯(lián)系人 [InverseProperty("PrimaryContactFor")] public Person PrimaryContact { get; set; } //第二聯(lián)系人 [InverseProperty("SecondaryContactFor")] Person SecondaryContact { get; set; }
(2)或使用Fluent API:
modelBuilder.Entity<Lodging>().HasOptional(l => l.PrimaryContact).WithMany(p => p.PrimaryContactFor); modelBuilder.Entity<Lodging>().HasOptional(l=>l.SecondaryContact).WithMany(p=>p.SecondaryContactFor)).Map(p => p.MapKey("SecondaryPersonID "));;
在生成的數(shù)據(jù)庫中為自動為Lodging表生成兩個外鍵:PrimaryContact _PersonID 和SecondaryPersonID
4、級聯(lián)刪除
1、如果兩個表之間存在一對多關(guān)系,Code First默認(rèn)會開啟兩個表之間的級聯(lián)刪除功能
數(shù)據(jù)庫里可以可視化的設(shè)置不級聯(lián)刪除,F(xiàn)luent API配置此外鍵關(guān)系時可以設(shè)置不級聯(lián)刪除:
this.HasMany(d => d.Lodgings).WithRequired(l => l.Destination).Map(l => l.MapKey("DestinationId")) //一對多并指定外鍵名 .WillCascadeOnDelete(false); // 關(guān)閉級聯(lián)刪除
2、也可以在上下文的OnModelCreating方法中移除這個默認(rèn)約定
modelBuilder.Conventions.Remove();
再需要開啟級聯(lián)刪除,則可以在FluentAPI關(guān)系映射中用. WillCascadeOnDelete(true) 單獨開啟
四、多對多關(guān)系
如果有兩個類中,各自都是導(dǎo)航屬性指向另一個類,Code First會認(rèn)為這兩個類之間是多對多關(guān)系,例如:
public class Trip { public int TripId { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public decimal CostUSD { get; set; } public byte[] RowVersion { get; set; } public List Activities { get; set; } } public class Activity { public int ActivityId { get; set; } [Required, MaxLength(50)] public string Name { get; set; } public List Trips { get; set; } }
Code First生成了一張中間表ActivityTrips,將另外兩張表的主鍵都作為外鍵關(guān)聯(lián)到了中間表上面。
中間表中字段的命名默認(rèn)為"[目標(biāo)類型名稱]_[目標(biāo)類型鍵名稱]".Activity_ActivityId 和Trip_TripId
并且也作為這個新的連接表的聯(lián)合主鍵。
指定表名
如果我們想指定中間表的名稱和鍵名稱,我們可以用Fluent API來配置。
modelBuilder.Entity<Trap>().HasMany(t => t.Activities).WithMany(a => a.Trips).Map(m => { m.ToTable("TripActivities"); m.MapLeftKey("TripIdentifier");//對應(yīng)Trip的主鍵 m.MapRightKey("ActivityId"); }); //或者 modelBuilder<Activity>.Entity().HasMany(a => a.Trips).WithMany(t => t.Activities).Map(m => { m.ToTable("TripActivities"); m.MapLeftKey("ActivityId");//對應(yīng)Activity的主鍵 m.MapRightKey("TripIdentifier"); });
到此這篇關(guān)于Entity Framework配置關(guān)系的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
winform下實現(xiàn)win7 Aero磨砂效果實現(xiàn)代碼
winform下實現(xiàn)win7 Aero磨砂效果實現(xiàn)代碼,需要的朋友可以參考下2012-03-03詳解C#中通過委托來實現(xiàn)回調(diào)函數(shù)功能的方法
這篇文章主要介紹了C#中通過委托來實現(xiàn)回調(diào)函數(shù)功能的方法,文中舉了一個典型的多線程回調(diào)程序?qū)嵗?需要的朋友可以參考下2016-04-04C#實現(xiàn)將選中復(fù)選框的信息返回給用戶的方法
這篇文章主要介紹了C#實現(xiàn)將選中復(fù)選框的信息返回給用戶的方法,涉及C#針對復(fù)選框操作的相關(guān)技巧,需要的朋友可以參考下2015-06-06c# 實現(xiàn)網(wǎng)頁加載后將頁面截取為長圖片
這篇文章主要介紹了c# 實現(xiàn)網(wǎng)頁加載后將頁面截取為長圖片的方法,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下2021-01-01