杨中科 EFCORE 第六部分 一对多关系配置

一对多关系配置

什么是实体间关系

1、所谓“关系数据库”
2、复习:数据库表之间的关系: 一对一、一对多、多对多。
3、EF Core不仅支持单实体操作,更支持多实体的关系操作。4、三部曲:实体类中关系属性;FluentAPI关系配置;使用关系操作。

一对多: 实体类

1、文章实体类Article、评论实体类Comment。一篇文章对应多条评论。

public class Article
{	
	public long Id { get; set;}
	public string Title( get; set;}
	public string Content{ get; set;}
	public List Comments { get; set;}= new List()
}
public class Comment
{
	public long Id { get; set; )
	public Article Article ( get; set; )
	public string Message ( get; set; )
}

示例:
新建Article类
杨中科 EFCORE 第六部分 一对多关系配置_第1张图片

新建Comment 类
杨中科 EFCORE 第六部分 一对多关系配置_第2张图片

一对一: 关系配置

EF Core中实体之间关系的配置的套路
Hasxxx(…).Withxxx(…)
有XXX、反之带有XXX
XXX可选值One、Many

对多: HasOne(…).WithMany(…);
一对一:HasOne(…).WithOne (…);
多对多:HasMany (…).WithMany(…);

一对一: 关系配置

class ArticleConfig :IEntityTypeConfiguration
{ public void Configure(EntityTypeBuilder
builder) { builder.ToTable("T Articles"); builder.Property(a =>a.Content).IsRequired().IsUnicode(); builder.Property(a =>a.Title).IsRequired().IsUnicode().HasMaxLength(255); } }

一对多: 关系配置

class CommentConfig :IEntityTypeConfiguration
{
	public void Configure(EntityTypeBuilderbuilder)
	{
		builder.ToTable("T_Comments");
		builder.HasOne
(c=>c.Article).WithMany(a =>a.Comments).IsRequired(); builder.Property(c=>c.Message).IsRequired0.IsUnicode(); } }

引入包
杨中科 EFCORE 第六部分 一对多关系配置_第3张图片

新建ArticleConfig
杨中科 EFCORE 第六部分 一对多关系配置_第4张图片

新建CommentConfig
杨中科 EFCORE 第六部分 一对多关系配置_第5张图片

新建 myDbcontext

杨中科 EFCORE 第六部分 一对多关系配置_第6张图片

执行迁移命令
在这里插入图片描述
在这里插入图片描述

查看数据库
杨中科 EFCORE 第六部分 一对多关系配置_第7张图片

杨中科 EFCORE 第六部分 一对多关系配置_第8张图片

一对一: 试验

1、迁移生成数据库表。
2、编写代码测试数据插入。
3、不需要显式为Comment对象的Article属性赋值 (当前赋值也不会出错),也不需要显式地把新创建的Comment类型的对象添加到DbContext中。EF Core会顺竿爬”

示例:
编写测试代码
只需要将父对象 插入Dbcontext中 ,即可
在这里插入图片描述

运行:
查看表数据
杨中科 EFCORE 第六部分 一对多关系配置_第9张图片
杨中科 EFCORE 第六部分 一对多关系配置_第10张图片

这样分别写也是同样的效果:
杨中科 EFCORE 第六部分 一对多关系配置_第11张图片

一对多关系数据的获取

获取关系数据

Article a =
ctx.Articles.Include(a=>a.Comments).Single(a=>aId==1);
Console.WriteLine(a.Title);foreach(Comment c in a.Comments)
{
	Console.WriteLine(c.Id+":"+c.Message);
}

Include定义在Microsoft.EntityFrameworkCore命名空间中。
查看一下生成的SQL语句

获取Id=2的 Article

杨中科 EFCORE 第六部分 一对多关系配置_第12张图片
运行结果:
杨中科 EFCORE 第六部分 一对多关系配置_第13张图片

文章下的所有评论

杨中科 EFCORE 第六部分 一对多关系配置_第14张图片
运行结果:
杨中科 EFCORE 第六部分 一对多关系配置_第15张图片
没有comment内容

设置断点查看一下
杨中科 EFCORE 第六部分 一对多关系配置_第16张图片
这种情况是不对的 ,按理应该有两条对应的评论

查看生成的sql语句,来查找问题所在
杨中科 EFCORE 第六部分 一对多关系配置_第17张图片
发现只查询了T-Articles没有关联查询T-Comment

解决方法,加上 include
表示插叙的时候,不仅查询Articles对应的表,也要关联查询Comment对应的表

修改之后
杨中科 EFCORE 第六部分 一对多关系配置_第18张图片
运行结果:
杨中科 EFCORE 第六部分 一对多关系配置_第19张图片
查看此时生成的sql语句
杨中科 EFCORE 第六部分 一对多关系配置_第20张图片

查询id=3对应的信息,以及文章信息

杨中科 EFCORE 第六部分 一对多关系配置_第21张图片
杨中科 EFCORE 第六部分 一对多关系配置_第22张图片
发生异常
TheArticle为null
杨中科 EFCORE 第六部分 一对多关系配置_第23张图片
此时生成的sql语句,没有查询Article对应的数据表
杨中科 EFCORE 第六部分 一对多关系配置_第24张图片

要想查询到数据,同样要使用include
杨中科 EFCORE 第六部分 一对多关系配置_第25张图片
此时运行结果:
杨中科 EFCORE 第六部分 一对多关系配置_第26张图片
对应生成的sql语句
杨中科 EFCORE 第六部分 一对多关系配置_第27张图片

额外的外键字段

上述操作中不是已经有了一个TheArticleId外键字段了吗?

虽然生成了外键,但是Comment实体中并没有对应表中TheArticleId字段的字段。
因为没有必要,TheArticle就能把对应的文章ID 取出来了

但是有的情况下,可能需要这一个属性,来单独获取外键值

为什么需要外键属性

1、EF Core会在数据表中建外键列。
2、如果需要获取外键列的值,就需要做关联查询,效率低。试一下。
3、需要一种不需要Join直接获取外键列的值的方式。

示例:
查询TheArticle 必须使用 include 关键字,此时查询是通过inner join 连接,但是此时Comment表中,是应该有 TheArtice这个字段的,是不需要连表查询的
杨中科 EFCORE 第六部分 一对多关系配置_第28张图片
生成的SQL语句
杨中科 EFCORE 第六部分 一对多关系配置_第29张图片

直接查询单表,就能查询到TheAricleId
杨中科 EFCORE 第六部分 一对多关系配置_第30张图片

方式一

首先,只想获取表中某些字段
杨中科 EFCORE 第六部分 一对多关系配置_第31张图片
结果:
在这里插入图片描述
运行的sql 语句
杨中科 EFCORE 第六部分 一对多关系配置_第32张图片
发现他 查询了 Id,Message,Title 都查出来了,但是此时用不上Message

使用Select 的映射操作,只获取需要的类型

在这里插入图片描述
此时,查看生成的SQL 语句

杨中科 EFCORE 第六部分 一对多关系配置_第33张图片

此时尝试,使用这种方式,能否获取到想要的数据,而不通过连表操作
杨中科 EFCORE 第六部分 一对多关系配置_第34张图片
运行的SQL
杨中科 EFCORE 第六部分 一对多关系配置_第35张图片
还是使用了连表查询

级联Select,获取数据,其实是不需要使用到include的,他是会在必要的使用自动加上include
这里把 include 关键字去掉,再次尝试
在这里插入图片描述
此时生成的SQL 语句 还是有 join 操作
杨中科 EFCORE 第六部分 一对多关系配置_第36张图片

正确的解决方法,单独给Comment 增加一个属性,和TheArticleI对应
杨中科 EFCORE 第六部分 一对多关系配置_第37张图片
由于不会对数据库造成任何改变,此时不需要,在执行 迁移命令
在关系中,告诉底层 ,新增的TheArticleId 就是外键列
杨中科 EFCORE 第六部分 一对多关系配置_第38张图片

此时修改代码
杨中科 EFCORE 第六部分 一对多关系配置_第39张图片

此时的sql 语句 便没有join操作
杨中科 EFCORE 第六部分 一对多关系配置_第40张图片

设置外键属性

1、在实体类中显式声明一个外键属性
2、关系配置中通过HasForeignKey(c=>c.ArticleId)指定这个属性为外键。
3、除非必要,否则不用声明,因为会引入重复

导航属性

由一个实体的属性,可以访问到另外一个实体的属性
杨中科 EFCORE 第六部分 一对多关系配置_第41张图片
杨中科 EFCORE 第六部分 一对多关系配置_第42张图片
这两者 都是导航属性,这种两则对应的属于,双向导航属性
杨中科 EFCORE 第六部分 一对多关系配置_第43张图片

有时双向的麻烦

有时,一些基础表,可能被多次引用

杨中科 EFCORE 第六部分 一对多关系配置_第44张图片
杨中科 EFCORE 第六部分 一对多关系配置_第45张图片

示例:

新建User 类
杨中科 EFCORE 第六部分 一对多关系配置_第46张图片
新建Leave类,请假
杨中科 EFCORE 第六部分 一对多关系配置_第47张图片
配置表,UserConfig
杨中科 EFCORE 第六部分 一对多关系配置_第48张图片
配置表 LeaveConfig
杨中科 EFCORE 第六部分 一对多关系配置_第49张图片
配置DBContext
杨中科 EFCORE 第六部分 一对多关系配置_第50张图片

配置方法

不设置反向的属性,然后配置的时候WithMany0不设置参数即可

杨中科 EFCORE 第六部分 一对多关系配置_第51张图片

执行数据迁移命令
杨中科 EFCORE 第六部分 一对多关系配置_第52张图片
在这里插入图片描述
查看数据库
杨中科 EFCORE 第六部分 一对多关系配置_第53张图片
查询数据测试

杨中科 EFCORE 第六部分 一对多关系配置_第54张图片
生成的sql语句
杨中科 EFCORE 第六部分 一对多关系配置_第55张图片
插入语句测试
杨中科 EFCORE 第六部分 一对多关系配置_第56张图片
数据库
杨中科 EFCORE 第六部分 一对多关系配置_第57张图片

选择

对于主从结构的“一对多”表关系,一般是声明双向导航属性。
而对于其他的“一对多”表关系: 如果表属于被很多表引用的基础表,则用单项导航属性,否则可以自由决定是否用双向导航属性。

关系配置在任何一方都可以

杨中科 EFCORE 第六部分 一对多关系配置_第58张图片

反着配置也可以

CommentConfig:
builder.HasOne

(c=>c.Article).WithMany(a=>a.Comments).IsRequired0;

ArticleConfig:
builder.HasMany(a=> a.Comments).WithOne(c =>c.Article).IsRequired0;

推荐策略

考虑到有单项导航属性的可能,我们一般用HasOne0.WithMany0;

对于user和 leave来说 ,只能配置在leave中,因为在user中没有反向导航属性。

自引用的组织结构树

杨中科 EFCORE 第六部分 一对多关系配置_第59张图片
代码表达

class OrgUnit
{
	public long Id { get; set; )
	public string Name { get; set; )
	public OrgUnit Parent ( get; set; )
	public List Children {get; set; } = newList0);
}

配置声明

builder.ToTable("T OrgUnits");
builder.Property(o =>o.Name).IsRequired().IsUnicode(.HasMaxLength(100);
builder.HasOne(u =>u.Parent).WithMany(p => p.Children);

示例:

新建实体类
杨中科 EFCORE 第六部分 一对多关系配置_第60张图片

新建config 类
杨中科 EFCORE 第六部分 一对多关系配置_第61张图片

新建mydbcontext
杨中科 EFCORE 第六部分 一对多关系配置_第62张图片

执行迁移命令
在这里插入图片描述
这个报错,是因为当前启动项目是 一对多1, 需要把当前项目设置为启动项目
杨中科 EFCORE 第六部分 一对多关系配置_第63张图片
在这里插入图片描述
在这里插入图片描述
查看数据库
杨中科 EFCORE 第六部分 一对多关系配置_第64张图片
外键关系
杨中科 EFCORE 第六部分 一对多关系配置_第65张图片

测试

1、测试数据插入
2、测试递归缩进打印
PrintChildren(int indentlevelTestDbContext ctx,OrgUnit parent)

测试数据插入

杨中科 EFCORE 第六部分 一对多关系配置_第66张图片
杨中科 EFCORE 第六部分 一对多关系配置_第67张图片
运行
查看数据库

杨中科 EFCORE 第六部分 一对多关系配置_第68张图片
思考:不是有关联关系的只要有一个保存进去,别的也会保存进去

删除数据库内容
杨中科 EFCORE 第六部分 一对多关系配置_第69张图片

断点调试

杨中科 EFCORE 第六部分 一对多关系配置_第70张图片
单项图,知道父节点,通过父节点无法知道子节点

建立双向关系
杨中科 EFCORE 第六部分 一对多关系配置_第71张图片
执行测试:
此时断点中,子节点有数据杨中科 EFCORE 第六部分 一对多关系配置_第72张图片
刷新数据库
杨中科 EFCORE 第六部分 一对多关系配置_第73张图片
方式二:
单项执行,多次加入
杨中科 EFCORE 第六部分 一对多关系配置_第74张图片
删除数据库中内容,重新生成
杨中科 EFCORE 第六部分 一对多关系配置_第75张图片
运行结果:
杨中科 EFCORE 第六部分 一对多关系配置_第76张图片

通过递归形式打印

杨中科 EFCORE 第六部分 一对多关系配置_第77张图片
调用:
杨中科 EFCORE 第六部分 一对多关系配置_第78张图片
运行结果:
杨中科 EFCORE 第六部分 一对多关系配置_第79张图片
杨中科 EFCORE 第六部分 一对多关系配置_第80张图片
运行结果:
杨中科 EFCORE 第六部分 一对多关系配置_第81张图片

你可能感兴趣的:(ASP.NET,数据库,.netcore)