P4-6 关系配置
关系配置
说明
- 1、所谓“关系数据库”
- 2、复习:数据库表之间的关系:一对一、一对多、多对多。
- 3、EF Core不仅支持单实体操作,更支持多实体的关系操作。
- 4、三部曲:
- 实体类中关系属性
- FluentAPI关系配置(这个是最复杂的)
- 使用关系操作
一对多
实体类
- 文章实体类Article
- 评论实体类Comment
- 一篇文章对应多条评论。
关系配置
EF Core中实体之间关系的配置的套路:
- HasXXX(…).WithXXX(…);
- 有XXX、反之带有XXX。
- XXX可选值One(一)、Many(多)
一对多:HasOne(…).WithMany(…);
一对一:HasOne(…).WithOne (…);
多对多:HasMany (…).WithMany(…);
关联数据的获取
一对多
- 获取关系数据(用EF Core常用下面两个)
- using Microsoft.EntityFrameworkCore;
- using System.Linq;
1
2
3
4
5
6
7
8Article a = ctx.Articles.Include(a=>a.Comments).Single(a=>a.Id==1);
Console.WriteLine(a.Title);
foreach(Comment c in a.Comments)
{
Console.WriteLine(c.Id+":"+c.Message);
}
//Include定义在Microsoft.EntityFrameworkCore命名空间中。
//查看一下生成的SQL语句
- 如果没有Include
- 去掉Include,再看一下运行效果。
- 去掉后,不会去用join连接另外一个表,无法多表联查
- 去掉Include,再看一下运行效果。
- 查看生成的SQL分析为什么。
- A连接B查询 和B连接A查询 运行的SQL查询语句不一样
- LEFT JOIN / INNER JOIN
1
2
3
4
5
6
7
8
9
10
11
12
13
14SELECT [t0].[Id], [t0].[Content], [t0].[Title], [t1].[Id], [t1].[ArticleId], [t1].[Message]
FROM (
SELECT TOP(2) [t].[Id], [t].[Content], [t].[Title]
FROM [T_Articles] AS [t]
WHERE [t].[Id] = CAST(1 AS bigint)
) AS [t0]
LEFT JOIN [T_Comments] AS [t1] ON [t0].[Id] = [t1].[ArticleId]
ORDER BY [t0].[Id], [t1].[Id]
SELECT TOP(2) [t].[Id], [t].[ArticleId], [t].[Message], [t0].[Id], [t0].[Content], [t0].[Title]
FROM [T_Comments] AS [t]
INNER JOIN [T_Articles] AS [t0] ON [t].[ArticleId] = [t0].[Id]
WHERE [t].[Id] = CAST(1 AS bigint)
实体类对象的关联追踪
- 只要我们的代码把实体类的关系设定了,EF Core就会顺竿爬
1 |
|
EF Core的“顺杆爬”
- 不需要显式为Comment对象的Article属性赋值(当前赋值也不会出错),也不需要显式地把新创建的Comment类型的对象添加到DbContext中。
- EF Core会“顺竿爬”。
- 杨中科老师的习惯是写全,不习惯让它顺杆爬,因为顺杆爬写着写着有可能自己都乱套了
关系的外键属性的设置
为什么需要额外的外键属性
- 了解即可,具体适合的案例可以看实体书中本章的内容
EF Core的SQL语句质量
- 数据库优化的原则
- 尽量不要select * from XXX
- 可以获取需要的列即可,会提升性能(但用EF Core的话,一般情况下不需要进行这种优化)
- EF Core自动生成的SQL语句质量
- 大部分查询比绝大部分程序员写出来的SQL性能都要高
- 只有少部分SQL语句性能可能不尽如人意,但是也影响不大。
- 特殊的一些SQL语句可能影响性能瓶颈,咱们在需要特殊优化
设置外键属性
- 1、在实体类中显式声明一个外键属性。
- 2、关系配置中通过HasForeignKey(c=>c.ArticleId)指定这个属性为外键。
- 3、除非必要,否则不用声明,因为会引入重复。
1 |
|
1 |
|
单项导航属性
- 对于主从结构的“一对多”表关系,一般是声明双向导航属性。
- 比如之前学的文章和评论的案例
- 而对于其他的“一对多”表关系:如果表属于被很多表引用的基础表,则用单项导航属性,否则可以自由决定是否用双向导航属性。
- 比如我有请假单,报销单,离职单等 但是都需要对应用户表。这种情况就适用于单项导航
单项导航属性的使用步骤
- 1.配置一端和多端
- 不设置反向的属性,然后配置的时候WithMany()不设置参数即可。
- 单项属性如果反向获取数据
1 |
|
关系配置在哪个实体类中
- 北京固安县和涿州市的故事
- 固安县叫中间这个路的名字为“固涿路”;而涿州市叫“涿固路”
- 站在不同的角度,就有不同的说法,但是本质上它们指的是同一个东西
- 所以
两张表的关系配置可以在任何一端
- 文章Article和评论Comment
- 文章叫“一对多” ; 而评论叫“多对一”
1 |
|
一对多
的推荐策略- 考虑到有单项导航属性的可能,我们一般用HasOne().WithMany()
- 建议都配置到
多的那一端
自引用的组织结构树
- 一种特殊的一对多案例
- 一种特殊的一对多案例
一对一
一对一关系
- 比如:订单–>快递单
一对一关系配置
- 1、
builder.HasOne<Delivery>(o => o.Delivery).WithOne(d => d.Order).HasForeignKey<Delivery>(d=>d.OrderId);
- 2、测试插入和获取数据。
- 注意:必须显式的在其中一个实体类中声明一个外键属性。
- 1、
1 |
|
多对多
- 描述
- 多对多的案例:老师–>学生
- 从EF Core 5.0开始,才正式支持多对多关系的支持
- 但还是需要中间表来保存两张表之间的对应关系
- 多对多实体和多对多关系配置
- 测试代码
- 数据插入
- 查询
基于关系的复杂查询
关系数据查询
- 1、查询评论中含有“微软”的所有的文章
- 2、同样效果的代码可能有多种写法,有时候要关注底层的SQL,看哪种方式最好。
- 确保系统在重要环节不会有明显的
性能瓶颈
1
2
3
4
5
6//第一种 exists
ctx.Articles.Where(a=>a.Comments.Any(c=>c.Message.Contains("微软")));
//第二种 inner join
ctx.Comments.Where(c => c.Message.Contains("微软")).Select(c => c.Article).Distinct();
- 确保系统在重要环节不会有明显的
例子
- 1、查询“所有由蜗牛快递负责的订单信息”
ctx.Orders.Where(o=>o.Delivery.CompanyName== “蜗牛快递”);
P4-6 关系配置
http://example.com/2024/09/22/Net Core2022教程/第4章:Entity Framework Core基础/P4-6 关系配置/