EF CodeFirst系列(6)---配置1对1,1对多,多对多关系
这一节介绍EF CodeFirst模式中的1对0/1,1对多,多对多关系的配置,只有梳理清楚实体间的关系,才能进行愉快的开发,因此这节虽然很简单但是还是记录了一下。
1. 1对0/1关系配置
1. 通过数据注释属性配置1对0/1关系
我们将要实现一个Student和StudentAddress实体的1对0/1关系,1对0/1关系指的是一个Student可有一个或者零个住址StudentAddress,但是一个StudentAddress必须对应一个Student。在数据库中表现形式是StudentId在Student表中是主键,StudentAddressId在数据库中同时是StudentAddress的主键和外键。实体类的代码如下:
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; } public virtual StudentAddress Address { get; set; }
} public class StudentAddress
{
[ForeignKey("Student")]
public int StudentAddressId { get; set; } public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public int Zipcode { get; set; }
public string State { get; set; }
public string Country { get; set; } public virtual Student Student { get; set; }
}
上边代码中会遵循EF CodeFirst默认约定,StudentId作为Students表的主键,StudentAddressId作为StudentAddresses表的主键,我们不需要自己去配置主键了,默认约定不会把StudentAddressId设置为指向Student实体的外键,这就我们需要自己去配置。在StudentAddressId通过[ForeignKey("Student")]修饰即可。
在1对0/1关系中,Student在没有StudentAddress时可以保存成功,但是StudentAddress没有分配Student时进行保存就会抛出异常。
2. 通过FluentApi配置1对0/1关系
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// 配置Student和StudentAddress实体
modelBuilder.Entity<Student>()
.HasOptional(s => s.Address) // 给Student设置可空的StudentAddress属性
.WithRequired(ad => ad.Student); //给StudentAddress设置不能为空的Student属性.没有Student时,StudentAddress不能保存
}
生成数据库如下:

2. 1对多关系配置
这一部分介绍EF中CodeFirst模式下1对多关系的配置,我们要实现Student和Grade的关系配置,一个学生只能有一个班级而一个班级可以有多个学生,实体类如下:
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; }
}
1.通过默认约定配置1对多关系
1.生成可空的外键(Student可以没有班级)
//Student实体中的Grade引用导航属性和Grade实体中的Students集合导航属性,两者有一个即可,生成的是可空的外键
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> Students { get; set; }
}
运行程序后生成的数据库如下,我们看到生成了可空的Grade_GradeId外键

2.生成不可空的外键(Student必须有班级)
生成不可空的外键也很简单,只要让默认的外键不为空即可,代码如下:
public class Student
{
public int Id { get; set; }
public string Name { get; set; } public int GradeId { get; set; }//如果改成 public int? GradeId则生成可空的外键
public Grade Grade { get; set; }
} public class Grade
{ public int GradeId { get; set; }
public string GradeName { get; set; } public ICollection<Student> Student { get; set; }
}
生成的数据库如下:

2. 通过FluentApi配置1对多关系
通常我们不需要配置1对多的关系,因为EF的默认约定就能帮我们很好地解决这个问题,如果为了让关系更好维护,我们也可以通过FluentApi来配置1对多关系。
FluentApi配置1对多关系代码如下:
public class SchoolContext : DbContext
{
public SchoolContext() : base()
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Grade> Grade { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasRequired(s => s.Grade)//Student有必需的导航属性Grade,这会创建一个not null的外键
.WithMany(g => g.Students)//Grade实体有集合导航属性Student
.HasForeignKey(s=> s.GradeId);//设置外键(如果Student中属性不遵循约定我们自己指定外键,如HasForeignKey(s=>s.GradeKey))
}
}
我们也可以通过Grade实体来实现Student和Grade的1对多关系,代码如下:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Grade>()
.HasMany(g => g.Students)
.WithRequired(s => s.Grade)
.HasForeignKey(s => s.GradeKey);
}
运行程序,生成的数据库如下:

3. 配置1对多的级联删除
级联删除指当删除父级记录时会自动删除子级记录,如删除班级时,将在这个班级的所有学生记录一并删除(EF中是将这个班级的Student中的GradeId列都设成null),通过FluentApi很容易配置级联删除。
modelBuilder.Entity<Grade>()
.HasMany<Student>(g => g.Students)
.WithRequired(s => s.CurrentGrade)
.WillCascadeOnDelete();//开启级联删除,删除班级时会一并删除所有这个班级的学生
//.WillCascadeOnDelete(false);不开启级联删除
一点补充:EF中的级联删除默认是打开的,EF中级联删除执行策略
1对1:如Student和StudentAddress,删除Student时会把StudentAddress一并删除。
1对多:如Student和Grade,删除Grade时,会把该年级下的学生的GradId设成为null。
多对多:见下边的Student和Course,删除一门课程时,会删除中间表中该门课程的记录。
3.配置多对多关系
1.通过默认约定配置多对多关系
这一部分介绍多对多关系的配置,以Student和Course为例,一个学生可以学多门课,每门课的学生可以是多个。EF6包含了多对多关系的默认约定。在Student实体类添加一个Course的集合导航属性,在Course实体类下添加一个Student集合导航属性,不需额外的配置,EF会帮我们创建Student和Course的多对多关系。代码如下:
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public ICollection<Course> Courses { get; set; }
} public class Course
{
public int CourseId { get; set; }
public string CourseName { get; set; }
public ICollection<Student> Students { get; set; }
} public class SchoolContext : DbContext
{
public SchoolContext() : base()
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Course> Grade { get; set; } }
运行程序后生成的数据库如下,EF创建了Courses,Students表,同时创建了一个StudentCourses中间表:

2.通过FluentApi配置多对多关系
直接上代码:
modelBuilder.Entity<Student>()
.HasMany<Course>(s => s.Courses)//配置一个学生有多个课程
.WithMany(c => c.Students) //配置一门课程有多个学生
.Map(cs =>
{
cs.MapLeftKey("StudentRefId"); //因为通过Entity<Student>()开始的,所以左表是Student
cs.MapRightKey("CourseRefId"); //右表是Course
cs.ToTable("StudentCourse"); //生成StudentCourse中间表
});
3.多对多的数据重置
在EF中如果中间表只有两个实体的主键列,那么EF会自动帮我们维护,一个重置学生课程的案例(常用的User-Role-Action权限控制也能这样重置角色和权限):
static void Main(string[] args)
{
using (SchoolContext context=new SchoolContext())
{
//必须要把对应的Courses查出来,不然添加时会报空指针异常
var stu1 = context.Students.Include("Courses").Where(s=>s.StudentId==).First(); var co1 = context.Courses.Find();
var co2= context.Courses.Find();
//先清空再添加
stu1.Courses.Clear();
stu1.Courses.Add(co1);
stu1.Courses.Add(co2);
context.SaveChanges();
}
}
EF CodeFirst系列(6)---配置1对1,1对多,多对多关系的更多相关文章
- 2.简单的Code First例子(EF Code-First系列)
现在假想,我们想要为讴歌学校创建一个应用程序,这个程序需要能够来添加或者更新学生,分数,教师还有课程信息. 代替之前我们的做法:先是创建数据库,现在我们不这么做,我们先来创建领域类,首先我来创建两个简 ...
- 3.Code-First 约定(EF Code-First系列)
前面,我们已经了解了Code-First利用领域类,怎么为我们创建数据库的简单示例.现在我们来学习一下Code-First约定吧. 什么是约定 约定说白了,就是基于一套规矩办事,这里就是基于你定义好的 ...
- EF CodeFirst 如何通过配置自动创建数据库<当模型改变时>
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 本篇为进阶篇,也是弥补自己之前没搞明白的地方,惭愧 ...
- EF CodeFirst系列(2)---CodeFirst的数据库初始化
1. CodeFirst的默认约定 1.领域类和数据库架构的映射约定 在介绍数据库的初始化之前我们需要先了解领域类和数据库之间映射的一些约定.在CodeFirst模式中,约定指的是根据领域类(如Stu ...
- 4.DB Initialization(数据库初始化)[EF Code-First系列]
前面的例子中,我们已经看到了Code-First自动为我们创建数据库的例子. 这里我们将要学习的是,当初始化的时候,Code-First是怎么决定数据库的名字和服务的呢??? 下面的图,解释了这一切! ...
- EF CodeFirst系列(3)---EF中的继承策略(暂存)
我们初始化数据库一节已经知道:EF为每一个具体的类生成了数据库的表.现在有了一个问题:我们在设计领域类时经常用到继承,这能让我们的代码更简洁且容易管理,在面向对象中有“has a”和“is a”关系 ...
- EF CodeFirst系列(5)---FluentApi
FluentApi总结 1.FluentApi简介 EF中的FluentApi作用是通过配置领域类来覆盖默认的约定.在EF中,我们通过DbModelBuilder类来使用FluentApi,它的功能比 ...
- EF Core中如何设置数据库表自己与自己的多对多关系
本文的代码基于.NET Core 3.0和EF Core 3.0 有时候在数据库设计中,一个表自己会和自己是多对多关系. 在SQL Server数据库中,现在我们有Person表,代表一个人,建表语句 ...
- 6.Configure Domain Classes(配置领域类)【EF Code-First 系列】
在前面的部分中,我们学习了Code-First默认约定,Code-First使用默认的约定,根据你的领域类,然后生成概念模型. Code-First模式,发起了一种编程模式:约定大于配置.这也就是说, ...
随机推荐
- 010 Editor v8.0.1(32 - bit) 算法逆向分析、注册机编写
010 Editor 的逆向分析整体算下来还是比较简单的,将程序拖入OD,通过字符串搜索定位到核心代码,经过分析,主要是如下图所示的两个关键函数,返回正确的值,才算是注册成功. 00409C9B 这个 ...
- Centos7 下Jenkins 安装
前言:什么是Jenkins? Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 一.下载 wg ...
- 如何展开Linux Memory Management学习?
Linux的进程和内存是两座大山,没有翻过这两座大山对于内核的理解始终是不完整的. 关于Linux内存管理,在开始之前做些准备工作. 首先bing到了Quora的<How can one rea ...
- 《PyQt5快速开发与实战了》正式发售 !!!
<PyQt5快速开发与实战>正式出售了,该书是国内第一本介绍PyQt5的书籍.是两位一线工程师耗费一年的心血.本书github网址:https://github.com/cxinping/ ...
- C#中UDP数据的发送、接收
Visual C# UDP数据的发送、接收包使用的主要类及其用法: 用Visual C# UDP协议的实现,最为常用,也是最为关键的类就是UdpClient,UdpClient位于命名空间System ...
- js获取response头信息
当我们使用ajax发起请求时,经常需要获取请求返回的头信息.默认情况下,js货可以获取如下头信息: Cache-Control Content-Language Content-Type Expirs ...
- jQuery对象与DOM对象之间的转换(转)
原文:https://www.cnblogs.com/lsy0403/p/5907084.html 什么是DOM对象 使用JavaScript中的方法获取页面中的元素返回的对象就是dom对象.比如使用 ...
- CodeForces 1151C Problem for Nazar
题目链接:http://codeforces.com/problemset/problem/1151/C 题目大意: 有一个只存奇数的集合A = {1, 3, 5……2*n - 1,……},和只存偶数 ...
- PS中如何提高修改psd图片的效率(自动选择工具)
在photoshop中制作图片的时候,一般要养成保留psd格式的习惯,纵然普通时候jpg,png格式常用,考虑到以后可能需要修改,也应该备份一下.如果考虑到以后需要修改,可每次成品保存成两个,一个ps ...
- Visual Studio 2019 (VS2019)正式版安装 Ankh SVN和VisualSVN插件
VS2019 正式版最近刚刚推出来,目前 Ankhsvn 还不支持,它最高只支持 VS2017,全网搜索了一下,也没有找到.在 Stackoverflow 上看了一下,找到这篇问答: 自己按照这种方法 ...