一对多(One-to-Many)关系:
下面,我们来介绍Code-First的一对多关系,比如,在一个Standard(年级)类中包含多个Student类。
如果想了解更多关于one-to-one,one-to-many,many-to-many关系的信息,请访问Entity Relationship
1.使用DataAnnotations配置One-to-Many关系:
如下代码所示:
public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } public virtual Standard Standard { get; set; } } public class Standard { public Standard() { Students = new List<Student>(); } public int StandardId { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } }
如上代码所示,Student实体类包含导航属性Standard,而且Standard实体类包含集合属性Student,这就是默认的一对多关系。
如果实体类遵循这种这种默认约定,也就是默认即是一对多关系了,我们就不需药额外的配置DataAnnotations或者Fluent API。
在数据库中,Code-First会通过在Student表中加入Standard_StandardId外键列来创建一对多关系。
我们建议在一个实体类中包含外键属性,如上代码中,如果在Student实体类中创建StandardId属性,它就会自动变成外键,因为它遵循了默认约定,即外键的格式应该为<类型名称>Id的格式。
同样的,如果我们创建的外键属性名字没有遵循默认的命名规定,那么我们就需要自己手动添加特性了,如下代码所示,Student类包含了一个StandardRefId属性:
public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } public int StandardRefId { get; set; } [ForeignKey("StandardRefId")] public virtual Standard Standard { get; set; } } public class Standard { public Standard() { StudentsList = new List<Student>(); } public int StandardId { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } }
如果代码,我们必须要给Standard属性加上[ForeignKey("StandardRefId")]特性,这样创建数据库的时候才会将StandardRefId设置为外键,数据库如下:
2.使用Fluent API配置One-to-Many关系:
还是拿上面两个类的例子
Student类和Standard类代码如下:
public class Student { public Student(){ } public int StudentId { get; set; } public string StudentName { get; set; } public int StandardId { get; set; } public virtual Standard Standard { get; set; } } public class Standard { public Standard() { StudentsList = new List<Student>(); } public int StandardId { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } }
使用Fluent API配置一对多关系代码:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //one-to-many modelBuilder.Entity<Student>() .HasRequired<Standard>(s => s.Standard) // Student entity requires Standard .WithMany(s => s.Students); // Standard entity includes many Students entities }
这是默认两个类的外键命名都遵循约定命名情况的时候,如果Student类包含了一个不遵循约定命名的外键名称呢,如下所示:
public class Student { public Student(){ } public int StudentId { get; set; } public string StudentName { get; set; } //StdId有一个不同于Code-First默认约定命名的名称 public int StdId { get; set; } public virtual Standard Standard { get; set; } } public class Standard { public Standard() { StudentsList = new List<Student>(); } public int StandardId { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } }
如上所示,StdId就没有遵循默认的<类型名称>Id的外键命名约定,所以我们的Fluent API配置如下:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //one-to-many modelBuilder.Entity<Student>() .HasRequired<Standard>(s => s.Standard) .WithMany(s => s.Students) .HasForeignKey(s => s.StdId); }
如你所见, modelBuilder.Entity<Student>().HasRequired<Standard>(s => s.Standard)
特别指定Student实体的Standard属性不能为空, .WithMany(s => s.Students).HasForeignKey(s => s.StdId)
指定了Standard实体包含多个Student实体,而且外键为StdId。
注意:每一个泛型方法都返回了一个该类型对象,所以才能有这种一串打点的写法^_^)
所以针对上面的配置代码,我们也可以以Standard类开头来写配置代码,如下所示:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //configure one-to-many modelBuilder.Entity<Standard>() .HasMany<Student>(s => s.Students) //Standard has many Students .WithRequired(s => s.Standard) //Student require one Standard .HasForeignKey(s => s.StdId);//Student includes specified foreignkey property name for Standard }
代码运行后将会创建如下的数据库:
注意StdId是不为空的列,所以每次加入和更新Students表的时候必须要指定Student实体类的Standard属性。
在One-to-Many关系中配置可空外键:
很简单,使用HasOptional方法代替HasRequired方法即可。
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //one-to-many modelBuilder.Entity<Student>() .HasOptional<Standard>(s => s.Standard) .WithMany(s => s.Students) .HasForeignKey(s => s.StdId); }
这样,Students表的StdId列就可为空了。
最近太忙了,工作上,生活上,总之,好事多磨吧,既然下定决心了要更下去,就不能食言。今天就先到这里吧,下篇将讲多对多关系的操作。