要專業系統地學習EF前往《你必須掌握的Entity Framework 6.x與Core 2.0》這本書的作者(汪鵬,Jeffcky)的博客:https://www.cnblogs.com/CreateMyself/
現在就來到了重中之重的配置了:一對多、多對多、一對一關系的配置,我這里全部使用Fulent API 的方式來
一對多
一對多最簡單了,寫好你的數據模型,什么配置都不用做,生成的表結構就是你想要的
來個簡單基類

public class BaseEntity { public BaseEntity() { this.Id = Guid.NewGuid().ToString(); this.AddTime = DateTime.Now; } public string Id { get; set; } public DateTime AddTime { get; set; } }
來個簡單圖書館類

public class Library:BaseEntity { public string Name { get; set; } public virtual ICollection<Book> Books { get; set; } }
來個簡單Book類

public class Book:BaseEntity { public string Name { get; set; } public virtual Library Library { get; set; } }
為他們公開DbSet屬性

public DbSet<Library> Librarys { get; set; } public DbSet<Book> Books { get; set; }
然后生成的表就是這樣的
在Book中有一個Library的外鍵,這是默認給生成的,你可能覺得這個外鍵名呢想以“FK_”開頭,還有表名你也不滿意,那行啊,來配置啊
咱們現在的配置就來專業一點,我們把對每一個model的配置單獨用一個類,最后通過反射的方式,把配置添加到上下文的OnModelCreating方法中
你的OnModelCreating中只需要這樣寫,就行了,上一篇我弄錯了

protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); var typeToRegister = Assembly.GetExecutingAssembly().GetTypes() .Where(x => !string.IsNullOrEmpty(x.Namespace)) .Where(x => x.BaseType != null && x.BaseType.IsGenericType && x.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in typeToRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(configurationInstance); } base.OnModelCreating(modelBuilder); }
你的配置代碼寫在哪里呢?請看我的項目文件結構
實體和配置分開放,便於管理,上下文里面你已經不用去管了
來看具體的配置

public class LibraryMap:EntityTypeConfiguration<Library> { public LibraryMap() { ToTable("tb_Librarys"); // 表名 HasKey(x => x.Id); // 主鍵 Property(x => x.Name); HasMany(x => x.Books).WithRequired(x => x.Library).HasForeignKey(x => x.FK_Library_Id); // 從圖書館的角度配置,一個圖書館有多本書,一本書必須屬於某一個圖書館,也可以從圖書的角度去配置 } }

public class BookMap:EntityTypeConfiguration<Book> { public BookMap() { ToTable("tb_Books"); HasKey(x => x.Id); // 從圖書的角度來配置是這樣的 // HasRequired(x => x.Library).WithMany(x => x.Books).HasForeignKey(x => x.FK_Library_Id); } }
現在生成的表就是我們想要的了
多對多
多對多也簡單,用學生和課程來舉例,一個學生可以學習多門課程,一門課程也可以供多名學生來學習
多對多的關系,在數據庫中我們需要建立第三張表專門維護兩者的關系。其中有兩種方法,通過配置 ,自動創建第三張表;或者你顯示的創建第三model

public class Student500:BaseEntity { public string Name { get; set; } public virtual ICollection<Course500> Courses500 { get; set; } }

public class Course500:BaseEntity { public string Name { get; set; } public virtual ICollection<Student500> Students500 { get; set; } }

public class Stduent500Map:EntityTypeConfiguration<Student500> { public Stduent500Map() { ToTable("tb_Students500"); HasKey(x => x.Id); HasMany(x => x.Courses500).WithMany(x => x.Students500) .Map(x => x.ToTable("tb_StudentCourses500") .MapLeftKey("Stduent500Id") .MapRightKey("Course500Id")); } }

public class Course500Map:EntityTypeConfiguration<Course500> { public Course500Map() { ToTable("tb_Courses500"); HasKey(x =>x.Id); Property(x => x.Name); } }
生成的表結構是這樣的
這應該是比較符合我們得期望了,我們來看一下顯示地創建第三個model,怎么弄。上面生成的StudentCourses500,他沒有自己的Id和AddTime,那么我們現在這樣做就行了
顯示定義第三個表來維護student和course的關系

public class Student100:BaseEntity { public string Name { get; set; } public byte Age { get; set; } public virtual ICollection<StudentCourse100> StudentCourse { get; set; } }

public class Course100:BaseEntity { public string Name { get; set; } public int ManimumStrength { get; set; } public virtual ICollection<StudentCourse100> StudentCourse { get; set; } }

public class StudentCourse100:BaseEntity { public string Student100Id { get; set; } public virtual Student100 Student100 { get; set; } public string Courses100Id { get; set; } public virtual Course100 Course100 { get; set; } }

public class Student100Map:EntityTypeConfiguration<Student100> { public Student100Map() { ToTable("tb_Student100"); HasKey(x => x.Id); HasMany(x => x.StudentCourse) .WithRequired(x => x.Student100) .HasForeignKey(x => x.Student100Id); } }

public class Course100Map:EntityTypeConfiguration<Course100> { public Course100Map() { ToTable("tb_Course100"); HasKey(x => x.Id); HasMany(x => x.StudentCourse) .WithRequired(x => x.Course100) .HasForeignKey(x => x.Courses100Id); } }
表結構如下
顯示定義第三張表,我們對這張表就有了更多的設置,只不過,添加數據時會有點繞

db.Students100.Add(new Student100 { Name = "王五", Age = 44, StudentCourse = new List<StudentCourse100> { new StudentCourse100{ Course100 = new Course100{ Name="生物",ManimumStrength=45} }, new StudentCourse100{ Course100 = new Course100{ Name="化學",ManimumStrength=45} }, new StudentCourse100{ Course100 = new Course100{ Name="歷史",ManimumStrength=45} } } }); db.SaveChanges();
一對一
弄這個之前我來引用一段《你必須知道的.Net Framework 6.x 與 Core 2.0》作者的原話:“正常情況下,首先應該探討一對一關系。但是如果使用過一對一關系,就會發現並不是那么簡單,換句話說,一對一關系最為復雜,設計如何使用HasOptional 與 WithRequired 、WithOptionalPrincipal 、
WithOptionalDependent”
來用人和聯系方式來舉例配置一對一關系

public class Person : BaseEntity { public string Name { get; set; } public virtual PersonContact PersonContact { get; set; } }

public class PersonContact : BaseEntity { public string Email { get; set; } public virtual Person Person { get; set; } }

public class PersonMap:EntityTypeConfiguration<Person> { public PersonMap() { ToTable("tb_Person"); HasKey(x => x.Id); HasOptional(x => x.PersonContact) .WithOptionalPrincipal(x => x.Person).Map(x => x.MapKey("FK_Person_Id")); } }

public class PersonContactMap:EntityTypeConfiguration<PersonContact> { public PersonContactMap() { ToTable("tb_PersonContact"); HasKey(x => x.Id); } }
表結構如下
上面我使用的是HasOptional、WithOptionalPrincipal來配置的,外鍵建立在PersonContact表上
principal主要的,dependent從屬的 那使用dependent 外鍵就會被建立在Person表上
當然還有其他的配置,這一點我就不說了,免得亂了,各位可以自己去研究。