12.翻译系列:EF 6 中配置一对多的关系【EF 6 Code-First系列】
EF 6 Code-First系列文章目录:
- 1 翻译系列:什么是Code First(EF 6 Code First 系列)
- 2.翻译系列:为EF Code-First设置开发环境(EF 6 Code-First系列)
- 3.翻译系列:EF Code-First 示例(EF 6 Code-First系列)
- 4.翻译系列:EF 6 Code-First默认约定(EF 6 Code-First系列)
- 5.翻译系列:EF 6中数据库的初始化(EF 6 Code-First 系列)
- 6.翻译系列:EF 6 Code-First中数据库初始化策略(EF 6 Code-First系列
- 7.翻译系列:EF 6中的继承策略(EF 6 Code-First 系列)
- 8.翻译系列: EF 6中配置领域类(EF 6 Code-First 系列)
- 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)
- 9.1 翻译系列:数据注解特性之----Table【EF 6 Code-First 系列】
- 9.2 翻译系列:数据注解特性之---Column【EF 6 Code First系列】
- 9.3 翻译系列:数据注解特性之Key【EF 6 Code-First 系列】
- 9.4 翻译系列:EF 6以及 EF Core中的NotMapped特性(EF 6 Code-First系列)
- 9.5 翻译系列:数据注解之ForeignKey特性【EF 6 Code-First系列】
- 9.6 翻译系列:数据注解之Index特性【EF 6 Code-First系列】
- 9.7 翻译系列:EF数据注解特性之--InverseProperty【EF 6 Code-First系列】
- 9.8 翻译系列:数据注解特性之--Required 【EF 6 Code-First系列】
- 9.9 翻译系列:数据注解特性之--MaxLength 【EF 6 Code-First系列】
- 9.10 翻译系列:EF数据注解特性之StringLength【EF 6 Code-First系列】
- 9.11 翻译系列:数据注解特性之--Timestamp【EF 6 Code-First系列】
- 9.12 翻译系列:数据注解特性之ConcurrencyCheck【EF 6 Code-First系列】
- 10.翻译系列:EF 6中的Fluent API配置【EF 6 Code-First系列】
- 10.1.翻译系列:EF 6中的实体映射【EF 6 Code-First系列】
- 10.2.翻译系列:使用Fluent API进行属性映射【EF 6 Code-First】
- 11.翻译系列:在EF 6中配置一对零或者一对一的关系【EF 6 Code-First系列】
- 12.翻译系列:EF 6 中配置一对多的关系【EF 6 Code-First系列】
- 13.翻译系列:Code-First方式配置多对多关系【EF 6 Code-First系列】
- 14.翻译系列:从已经存在的数据库中生成上下文类和实体类【EF 6 Code-First系列】
- 15.翻译系列:EF 6中的级联删除【EF 6 Code-First 系列】
- 16.翻译系列:EF 6 Code -First中使用存储过程【EF 6 Code-First系列】
- 17.翻译系列:将Fluent API的配置迁移到单独的类中【EF 6 Code-First系列】
- 18.翻译系列:EF 6 Code-First 中的Seed Data(种子数据或原始测试数据)【EF 6 Code-First系列】
- 19.翻译系列:EF 6中定义自定义的约定【EF 6 Code-First约定】
- 20.翻译系列:Code-First中的数据库迁移技术【EF 6 Code-First系列】
- 20.1翻译系列:EF 6中自动数据迁移技术【EF 6 Code-First系列】
- 20.2.翻译系列:EF 6中基于代码的数据库迁移技术【EF 6 Code-First系列】
- 21.翻译系列:Entity Framework 6 Power Tools【EF 6 Code-First系列】
这里我们将学习如何在两个实体(领域类)之间配置一对多的关系。
我们使用Student和Grade两个实体配置一对多的关系,一个Grade中可以有很多的Students。
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
}
在上面两个实体实现一对多关系之后,数据库中就会生成下面两个表:

一对多的关系,可以通过下面的方式进行配置:
- 通过默认的约定
- 使用Fluent API进行配置
通过默认约定配置一对多的关系
在EF中有某些约定,只要实体遵循这些约定,EF就会为我们在数据库自动生成一对多的关系数据表。你不用进行任何其他的配置。
我们来看看一对多关系的所有的约定情况吧:
约定1:
我们想要在Student实体和Grade实体之间建立一对多的关系,并且很多学生关联到一个Grade。这就意味着,每一个Student实体指向一个Grade。这种情况可以通过在Student类中包含一个Grade类型的导航属性做到,例如:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Grade Grade { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
}
在上面的例子中,Student类包含了一个Grade类型的导航属性,这样就会在Students和Grades表之间生成一对多关系,并且生成外键Grade_GradeId:

请注意:因为应用类型的属性是可空的,所以在Students表中创建的外键列Grade_GradeId是可空的。你可以使用Fluent API配置不为空的外键列。
约定2:
另外一个约定就是,在主体实体中包含一个集合类型的导航属性,例如:
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public ICollection<Student> Students { get; set; }
}
在上面例子中Grade实体中包含一个集合类型ICollection的导航属性Students.所以这种也会在Students和Grades表之间生成一对多的关系。生成的数据库结构和约定1中一样。
约定3:
在两个实体中,都包含导航属性:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Grade Grade { get; set; }
}
public class Grade
{
public int GradeID { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public ICollection<Student> Student { get; set; }
}
在上面的代码中,Student实体包含一个Grade类型的导航属性,同样,Grade实体包含一个集合类型ICollection的属性.结果也是在两个表之间生成一对多的关系。生成的数据库结果和约定1,约定2中一样。
约定4:
在两个实体中,完整的定义关系,也会根据约定生成一对多的关系表:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int GradeId { get; set; }
public Grade Grade { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public ICollection<Student> Student { get; set; }
}
在上面的例子中,Student实体中,包含一个外键属性GradeId,还有一个Grade类型的导航属性。这样就会生成一对多的关系表。并且Student表中生成的外键GradeId是不可空的:
如果GradeId是可空的int类型,那么就会生成可空的外键:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int? GradeId { get; set; }
public Grade Grade { get; set; }
}
上面的代码将会生成一个可空的外键GradeId,?只是类型Nullable的简写。
使用Fluent API配置一对多的关系
通常情况下,在EF中你不用配置一对多的关系,因为默认的约定,已经帮我们配置好了。然而你可以使用Fluent API来配置一对多的关系,比默认生成的表更好维护一点。
看看下面的Student和Grade实体:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int CurrentGradeId { get; set; }
public Grade CurrentGrade { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public ICollection<Student> Students { get; set; }
}
你可以使用Fluent API,重写上下文类中的OnModelCreating方法,来给上面的代码配置一对多的关系:
public class SchoolContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Grade> Grades { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// configures one-to-many relationship
modelBuilder.Entity<Student>()
.HasRequired<Grade>(s => s.CurrentGrade)
.WithMany(g => g.Students)
.HasForeignKey<int>(s => s.CurrentGradeId);
}
}
我们来一步步理解上面的代码:
- 首先从一个实体类开始配置,所以modelBuilder.Entity()就是从Student实体开始配置。
- 然后,.HasRequired(s => s.CurrentGrade)指定Student实体,必须要有CurrentGrade属性,这就会在数据库中生成一个不为空的外键。
- 现在,现在就是配置关系的另外一边,也就是Grade实体。
- .WithMany(g => g.Students)指定Grade实体包含很多Student实体,这里可以通过ICollcetion类型的属性推断出来。
- 然后,如果Student实体,不遵循外键的约定【ID property convention】,我们就可以通过HasForeignKey方法指定外键的名称。
- HasForeignKey(s => s.CurrentGradeId),指定了Student实体中的外键属性。
还有另外一种方式配置一对多关系,就是从Grade实体开始配置,而不是Student实体。下面的代码,生成的数据库和上面的代码生成的是一样的:
modelBuilder.Entity<Grade>()
.HasMany<Student>(g => g.Students)
.WithRequired(s => s.CurrentGrade)
.HasForeignKey<int>(s => s.CurrentGradeId);
代码生成的数据库结构如下:

使用Fluent API配置不为空的外键列
在约定1中,我们看到生成的一对多关系中,外键是可空的,为了生成不为空的外键列,我们可以这样,使用HasRequired方法:
modelBuilder.Entity<Student>()
.HasRequired<Grade>(s => s.CurrentGrade)
.WithMany(g => g.Students);
使用Fluent API配置级联删除
级联删除意味着:当父行被删除之后,自动删除相关的子行。例如:如果Grade被删除了,那么所有在这个Grade中的Students应该同样被自动删除。下面的代码,使用WillCascadeOnDelete方法配置级联删除:
modelBuilder.Entity<Grade>()
.HasMany<Student>(g => g.Students)
.WithRequired(s => s.CurrentGrade)
.WillCascadeOnDelete();
好了,一对多的关系就介绍到这里,下面一节讲解多对多关系。
12.翻译系列:EF 6 中配置一对多的关系【EF 6 Code-First系列】的更多相关文章
- 11.翻译系列:在EF 6中配置一对零或者一对一的关系【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-fi ...
- 8.翻译系列: EF 6中配置领域类(EF 6 Code-First 系列)
原文地址:http://www.entityframeworktutorial.net/code-first/configure-classes-in-code-first.aspx EF 6 Cod ...
- 20.1翻译系列:EF 6中自动数据迁移技术【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/automated-migration-in-code-first.aspx EF 6 ...
- 20.翻译系列:Code-First中的数据库迁移技术【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/migration-in-code-first.aspx EF 6 Code-First ...
- 19.翻译系列:EF 6中定义自定义的约定【EF 6 Code-First约定】
原文链接:https://www.entityframeworktutorial.net/entityframework6/custom-conventions-codefirst.aspx EF 6 ...
- 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)
原文地址:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF 6 Code-F ...
- css3笔记系列-3.css中的各种选择器详解,不看后悔系列
点击上方蓝色字体,关注我 最详细的css3选择器解析 选择器是什么? 比较官方的解释:在 CSS 中,选择器是一种模式,用于选择需要添加样式的元素. 最常见的 CSS 选择器是元素选择器.换句话说 ...
- CentOS7系列--5.3CentOS7中配置和管理Kubernetes
CentOS7配置和管理Kubernetes Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展.如果你曾经用过Docker容器技术部署容器,那么可以将D ...
- CentOS7系列--5.2CentOS7中配置和管理Docker
CentOS7配置和管理Docker Docker是操作系统级别的虚拟化工具,它能自动化布署在容器中的应用 1. 安装Docker 1.1. 安装Docker相关软件 [root@server1 ~] ...
随机推荐
- Mysql innodb_fast_shutdown
innodb_fast_shutdown有3个值: 默认是1 可选0 1 2 支持全动态局设置 使用场景:在做数据库关闭升级的时候 set global innodb_fast_shutdown=0 ...
- Color the ball HDU1556
这题整整debug了两个小时 不同组居然要初始化 本以为built函数里面已经初始化好了!!!!! 其他无需注意 #include<cstdio> #include<cstring ...
- 如何查看Ubuntu版本,以及Linux内核版本??
查看Ubuntu版本: 方法一: cat /etc/issue 方法二: sudo lsb_release -a 查看内核版本: uname -r
- NumPy学习(索引和切片,合并,分割,copy与deep copy)
NumPy学习(索引和切片,合并,分割,copy与deep copy) 目录 索引和切片 合并 分割 copy与deep copy 索引和切片 通过索引和切片可以访问以及修改数组元素的值 一维数组 程 ...
- rabbitmq学习(七) —— springboot下的可靠使用
前面的学习都是基于原生的api,下面我们使用spingboot来整合rabbitmq springboot对rabbitmq提供了友好支持,极大的简化了开发流程 引入maven <depende ...
- [洛谷P2123]皇后游戏
很抱歉,这个题我做的解法不是正解,只是恰巧卡了数据 目前数据已经更新,这个题打算过一段时间再去写. 目前在学习DP,这个会暂时放一放,很抱歉 这个题是一个国王游戏的变形(国王游戏就把我虐了qwq) 题 ...
- spring整合mybatisXML版
引用的所有jar包,本demo是一个普通的java项目测试的: aopalliance.jarasm-3.3.1.jaraspectjweaver.jarcglib-2.2.2.jarcommons- ...
- Java定时线程池停止超时任务
一.背景题主最近遇到一个问题,本来通过ScheduledExecutorService线程池定时调度一个任务.奈何不知道为啥跑了2个多月,其中一个任务Hang住了,原本定时的任务则出现了问题. 关于定 ...
- ECS之旅——常用的linux指令
玩过Linux的人都会知道,Linux中的命令的确是非常多,但是玩过Linux的人也从来不会因为Linux的命令如此之多而烦恼,因为我们只需要掌握我们最常用的命令就可以了.当然你也可以在使用时去找一下 ...
- C# 调用windows api 操作鼠标、键盘、窗体合集...更新中
鼠标操作window窗体合集...更新中 1.根据句柄查找窗体 引自http://www.2cto.com/kf/201410/343342.html 使用SPY++工具获取窗体 首先打开spy+ ...