在開發過程中,學生和教室的關系(一個學生只能對應一個教室,一個教室對應多個學生),部門的領導和部門的職員等,幾乎無處不在。
以學生和教室的關系:在學校中,一個學生必須對應一個班級,如果一個好學生的話,他不僅對應一個班級,而且學校還會再開一個學霸班在休息日或者放學后進行上課。所以分析:學生必須對應一個班級(一對多關系),但是一個學生可能會對應一個學霸班(有的學生在學霸班,有的學生不能上學霸班)。
1.創建數據庫中的表:
Class3表
Id --編號(int)
Name --班級名稱(nvarchar(50))
Student3表
Id --編號(int)
Name --學生名稱(nvarchar(50))
ClassId --班級編號(int,外鍵關聯Class3的Id)
SYClassId --特殊班級編號(int,外鍵關聯Class3的Id)
2.安裝EntityFramework框架 -- Install-Package EntityFramework
3.創建實體類(Student3,Class3)
public class Class3 { public int Id { get; set; } public string Name { get; set; } }
public class Student3 { public int Id { get; set; } public string Name { get; set; } public int ClassId { get; set; } //int?表示對應字段的表中的列可以為空 public int? SYClassId { get; set; } //對應外鍵,要聲明一個關於外鍵關聯的主鍵表的類型,並且命名方式:外鍵:名Id(或名_Id);對應的外鍵的主鍵表類型是外鍵名減去Id public virtual Class3 Class { get; set; } public virtual Class3 SYClass { get; set; } }
4.創建Student3和Class3的配置類
public class Class3Config:EntityTypeConfiguration<Class3> { public Class3Config() { this.ToTable("T_Classes3"); } }
public class Students3Config:EntityTypeConfiguration<Student3> { public Students3Config() { this.ToTable("T_Students3"); this.HasRequired(s => s.Class).WithMany().HasForeignKey(c => c.ClassId); this.HasOptional(s => s.SYClass).WithMany().HasForeignKey(c => c.SYClassId); } }
其中定義的規則就是:Has...(s=>s.外鍵的主鍵表類型).with...().ForeignKey(外鍵);
判斷規則:從左向右,例如:學生必須對應一個班級,一個班級一定對應多個學生,所以就是選擇HasRequired->WithMany;學生可能對應一個特殊班級,一個特殊班級一定對應多個學生,所以選擇:HasOptional->WithMany
5.創建繼承DbContext的子類Test3DbContext,添加無參數的構造函數,重寫OnModelCreating方法
public class Test3DbContext:DbContext { public Test3DbContext():base("name=conn1") { } public DbSet<Class3> Classes3 { get; set; } public DbSet<Student3> Students3 { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly()); } }
幾點重要的注意點:
(1)base()里面要寫數據庫字符串連接名稱
(2)有多個個實體類,創建多少個DbSet<T>類型的屬性
6.實現一對多關系,添加到數據庫中
Test3DbContext tdc3 = new Test3DbContext(); Class3 cls1 = new Class3(); cls1.Name = "初一1班"; tdc3.Classes3.Add(cls1); Class3 cls2 = new Class3(); cls2.Name = "初一2班"; tdc3.Classes3.Add(cls2); Class3 cls3 = new Class3(); cls3.Name = "學霸先進班"; tdc3.Classes3.Add(cls3); Student3 s1 = new Student3(); s1.Name = "張三"; s1.Class = cls1; tdc3.Students3.Add(s1); Student3 s2 = new Student3(); s2.Name = "李四"; s2.Class = cls2; s2.SYClass = cls3; tdc3.Students3.Add(s2); tdc3.SaveChanges(); Console.WriteLine("ok"); Console.ReadKey();
注意點:
1.在Student3實體類中添加Class3數據類型的屬性,屬性名不一定非要叫這個,只是習慣外鍵去掉Id,但是必須要添加virtual
2.對於可空字段:引用類型是默認可空的,值類型字段需要long? 、int?
3.對於一對多關系,可以在Class3中配置public virtual ICollection<Student3> Students{get;set;} = new List<Students>();屬性。最好給這個屬性初始化一個對象,而這樣初始化一個對象只能在C#6.0中使用,如果6.0以下的話需要在構造函數中進行初始化。建議不要這樣使用,因為會造成耦合度高。
使用:
Test3DbContext tdc3 = new Test3DbContext();
Class3 c1 = new Class3{Name="高一1班"};
tdc3.Classes3.Add(c1);
Student3 s1 = new Student3{Name="張三"};
Student3 s2 = new Student3{Name="李四"};
c1.Students.Add(s1);//相當於將s1對象的學生加入到了c1對象的班級中
4.一對多的配置:(在每個實體類的配置類中進行配置)
(1)關系映射基本套路:this.Has***(p=>p.AAA).With***().HasForeignKey(s=>s.AAAId); 當前表和AAA屬性的表的關系是:當前表->AAA對應的數據類型的表的對應關系,With***AAA對應當前表的關系。
HasOptional() 有一個可選的(可以為空)
HasRequired() 必須有一個(不能為空)
HasMany() 有很多
同理:
WithOption()
WithRequired()
WithMany()
5.Fluent API的配置
(1)HasMaxLength設定字段的最大長度
this.Property(p=>p.Name).HasMaxLength(50)設置Name屬性長度為50
當如果使用Name字段插入一個超出50長度的字符串,會報DbEntityValidationException異常,這個異常的Message中看不到詳細的錯誤消息,要看EntityValidationException屬性的值,具體如下:
。。。
。。。
try
{
tdc3.SaveChanges();
}
catch(DbEntityValidationException ex)
{
StringBuilder sb = new StringBuilder();
foreach(var ve in ex.EntityValidationErrors.SelectMany(eve=>eve.ValidationErrors))
{
sb.AppendLine(ve.PropertyName+":"+ve.ErrorMessage);
}
Console.WriteLine(sb);
}
(2)字段是否可空(針對於引用類型)
this.Property(p=>p.Name).IsRequired()屬性不能為空
this.Property(p=>p.Name).IsOptional() 屬性可以為空(雞肋,原因是引用類型默認為空)
(3)主鍵如果不是默認的Id,那么就需要配置
主鍵:this.HasKey(p=>p.pId);
(4)this.Property(p=>p.Name).IsUnicode(false);對應的數據類型是varchar類型。IsUnicode(false)表示varchar類型,IsUnicode(true)表示nvarchar類型
(5)this.Property(p.p.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity) 指定字段是自動增長類型