2.4.5 EF Core -- 查询

  • 关联数据加载
  • 客户端与服务端运算
  • 跟踪与不跟踪
  • 复杂查询运算
  • 原生 SQL 查询
  • 全局查询筛选器

关联数据加载

学员和助教都在项目分组中,调整模型,删除 Assistant

ProjectGroup 添加 Member 列表

public List<Member> Members { get; set; }

Member 添加 是否助教判断,分组信息

public bool IsAssistant { get; set; }public string GroupId { get; set; }public ProjectGroup Group { get; set; }

Task 添加 学员信息

public Member Member { get; set; }

接下来为每一个表添加一个控制器

一个 Project 对应多个 ProjectGroup

ProjectGroup

namespace LighterApi.Controller
{[ApiController][Route("api/[controller]")]public class ProjectGroupController : ControllerBase{private readonly LighterDbContext _lighterDbContext;public ProjectGroupController(LighterDbContext lighterDbContext){_lighterDbContext = lighterDbContext;}[HttpPost]public async Task<IActionResult> Create([FromBody] ProjectGroup group){_lighterDbContext.ProjectGroups.Add(group);await _lighterDbContext.SaveChangesAsync();return StatusCode((int) HttpStatusCode.Created, group);}[HttpGet][Route("{id}")]public async Task<IActionResult> GetAsync(string id, CancellationToken cancellationToken){var project = await _lighterDbContext.Projects.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);return Ok(project);}}
}

迁移

dotnet ef migrations add RefactoryProjectEntitiesdotnet ef database update

Entity 主键添加自动生成

/// <summary>
/// 主键Id
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }

启动程序,Postman 访问

ProjectController

[HttpGet]
[Route("{id}")]
public async Task<IActionResult> GetAsync(string id, CancellationToken cancellationToken)
{var project = await _lighterDbContext.Projects.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);return Ok(project);
}

查询项目信息,发现分组信息 groups 为空

因为 EF 默认不会查询关联数据,所以需要实现一下

ProjectController 获取项目时使用 Include

[HttpGet]
[Route("{id}")]
public async Task<IActionResult> GetAsync(string id, CancellationToken cancellationToken)
{var project = await _lighterDbContext.Projects.Include(p => p.Groups).FirstOrDefaultAsync(p => p.Id == id, cancellationToken);return Ok(project);
}

由于项目中有分组引用,分组中有项目引用,所以需要在序列化的时候处理循环引用

Startup

services.AddControllers().AddNewtonsoftJson(x=>x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);

这样就可以查到项目信息

EF Core 为我们提供了三种加载数据的方式

  • 预先加载
  • 显式加载
  • 延迟加载

加载相关数据:https://docs.microsoft.com/zh-cn/ef/core/querying/related-data/

预先加载

预先加载表示从数据库中加载关联数据,作为初始查询的一部分。

在以下示例中,结果中返回的blogs将使用关联的posts填充其 Posts 属性。

using (var context = new BloggingContext())
{var blogs = context.Blogs.Include(blog => blog.Posts).ToList();
}

显式加载

显式加载表示稍后从数据库中显式加载关联数据。

可以通过 DbContext.Entry(...) API 显式加载导航属性。

using (var context = new BloggingContext())
{var blog = context.Blogs.Single(b => b.BlogId == 1);context.Entry(blog).Collection(b => b.Posts).Load();context.Entry(blog).Reference(b => b.Owner).Load();
}

ProjectController

// 显式加载
var project = await _lighterDbContext.Projects.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
await _lighterDbContext.Entry(project).Collection(p => p.Groups).LoadAsync(cancellationToken);

延迟加载

延迟加载表示在访问导航属性时,从数据库中以透明方式加载关联数据。

使用延迟加载的最简单方式是通过安装 Microsoft.EntityFrameworkCore.Proxies 包,并通过调用 UseLazyLoadingProxies 来启用该包。

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)=> optionsBuilder.UseLazyLoadingProxies().UseSqlServer(myConnectionString);

或在使用 AddDbContext 时:

.AddDbContext<BloggingContext>(b => b.UseLazyLoadingProxies().UseSqlServer(myConnectionString));

EF Core 接着会为可重写的任何导航属性(即,必须是 virtual 且在可被继承的类上)启用延迟加载。 例如,在以下实体中,Post.Blog 和 Blog.Posts 导航属性将被延迟加载。

public class Blog
{public int Id { get; set; }public string Name { get; set; }public virtual ICollection<Post> Posts { get; set; }
}public class Post
{public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }public virtual Blog Blog { get; set; }
}

Project

public virtual ICollection<ProjectGroup> Groups { get; set; }

ProjectController

// 延迟加载
project.Groups// 引用到属性时才加载

客户端与服务端运算

客户端与服务端运算:https://docs.microsoft.com/zh-cn/ef/core/querying/client-eval

由于 SQL Server 提供程序不了解此方法的实现方式,因此无法将其转换为 SQL。 查询的所有其余部分是在数据库中评估的,但通过此方法传递返回的 URL 却是在客户端上完成。

var blogs = context.Blogs.OrderByDescending(blog => blog.Rating).Select(blog => new{Id = blog.BlogId,Url = StandardizeUrl(blog.Url)// 服务端转换SQL,不了解客户端方法实现}).ToList();public static string StandardizeUrl(string url)
{url = url.ToLower();if (!url.StartsWith("http://")){url = string.Concat("http://", url);}return url;
}

需要区分数据运算最终在客户端,还是服务端运行

循环中获取分组会导致多次查询数据库

foreach (var project in _lighterDbContext.Projects)
{project.Groups// 多次查询数据库
}

应该一次性查询

var projects = _lighterDbContext.Projects.ToList();

跟踪与不跟踪

跟踪与不跟踪:https://docs.microsoft.com/zh-cn/ef/core/querying/tracking

默认情况下,跟踪返回实体类型的查询。 这表示可以更改这些实体实例,然后通过 SaveChanges() 持久化这些更改。

非跟踪查询

var blogs = context.Blogs.AsNoTracking().ToList();

还可以在上下文实例级别更改默认跟踪行为:

context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;var blogs = context.Blogs.ToList();

复杂查询运算

复杂查询运算:https://docs.microsoft.com/zh-cn/ef/core/querying/complex-query-operators

联接

var query = from photo in context.Set<PersonPhoto>()join person in context.Set<Person>()on photo.PersonPhotoId equals person.PhotoIdselect new { person, photo };

GroupJoin

var query = from b in context.Set<Blog>()join p in context.Set<Post>()on b.BlogId equals p.PostId into groupingselect new { b, grouping };

SelectMany

var query = from b in context.Set<Blog>()from p in context.Set<Post>()select new { b, p };

GroupBy

var query = from p in context.Set<Post>()group p by p.AuthorId into gselect new{g.Key,Count = g.Count()};

Left Join

var query = from b in context.Set<Blog>()join p in context.Set<Post>()on b.BlogId equals p.BlogId into groupingfrom p in grouping.DefaultIfEmpty()select new { b, p };

原生 SQL 查询

原生 SQL 查询:https://docs.microsoft.com/zh-cn/ef/core/querying/raw-sql

var blogs = context.Blogs.FromSqlRaw("SELECT * FROM dbo.Blogs").ToList();

全局查询筛选器

全局查询筛选器:https://docs.microsoft.com/zh-cn/ef/core/querying/filters

modelBuilder.Entity<Blog>().HasQueryFilter(b => EF.Property<string>(b, "_tenantId") == _tenantId);
modelBuilder.Entity<Post>().HasQueryFilter(p => !p.IsDeleted);

所有实体都继承了基类 Entity,所以这样会把过滤器添加在所有查询上面

LighterDbContext

modelBuilder.Entity<Entity>().HasQueryFilter(x => x.TenantId == "");

GitHub源码链接:

https://github.com/MINGSON666/Personal-Learning-Library/tree/main/ArchitectTrainingCamp/LighterApi

ef 多个左联接查询_.NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记...相关推荐

  1. efcore 实体配置_.NET 云原生架构师训练营(模块二 基础巩固 EF Core 基础与配置)--学习笔记...

    2.4.3 EF Core -- 基础与配置连接字符串 异步编程 日志 DbContext池 类和配置表 属性和列配置 并发token 索引 连接字符串 在 http://ASP.NET Core 配 ...

  2. .NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记

    2.4.5 EF Core -- 查询 关联数据加载 客户端与服务端运算 跟踪与不跟踪 复杂查询运算 原生 SQL 查询 全局查询筛选器 关联数据加载 学员和助教都在项目分组中,调整模型,删除 Ass ...

  3. 管理节点连接不上sql节点_华为云IEF智能边缘平台十万边缘节点管理技术深度解读学习笔记...

    华为云智能边缘平台IEF首席架构师张琦在3月27-28日举办的华为开发者大会2020(Cloud)上,深度解读了十万边缘节点的管理技术,以及如何通过云原生技术和边缘计算结合,构建边缘计算实战场景中所需 ...

  4. 微服务的好处与弊端_在云原生时代,就一定要用微服务吗?

    微服务架构可谓是当前软件开发领域的技术热点,它在各种博客.知识媒体和业界知名会议演讲上的出镜率非常之高,无论是做基础架构还是做业务系统的工程师,对微服务都相当关注,而这个现象与热度已经持续了近 5 年 ...

  5. python爬虫架构师之路_一位资深 架构师大牛给予Java技术提升的学习路线建议

    一位资深 架构师大牛给予Java技术提升的学习路线建议 对于工作多年的程序员而言,日后的职业发展无非是继续专精技术.转型管理和晋升架构师三种选择. 架构师在一家公司有多重要.优秀架构师需要具备怎样的素 ...

  6. python 按需加载_基于python的opcode优化和模块按需加载机制研究(学习与个人思路)(原创)...

    基于python的opcode优化和模块按需加载机制研究(学习与思考) 姓名:XXX 学校信息:XXX 主用编程语言:python3.5 文档转换为PDF有些图片无法完全显示,请移步我的博客查看 完成 ...

  7. 使用通用mapper实现条件查询_【微服务】152:Stream流和通用mapper批量查询的使用...

    今天是刘小爱自学Java的第152天. 感谢你的观看,谢谢你. 学习计划安排如下: 补充完昨天商品查询中关于分类和品牌的部分,其中牵扯到了两个非常重要的知识点: Stream流的使用,这个学过后基本就 ...

  8. java金蝶云单据查询_金蝶云苍穹单据列表开发demo

    控件使用 列表分组字段 在左侧大纲中选择表格视图后在实体列表元素中选择列表字段分组,而后将申请数据和已订货数量拖进列表分组字段中,并更改列表分组字段名称为数量 合并列表字段 同上述步骤一样,只不过在实 ...

  9. @autowired注解原理_相见恨晚,一个架构师也不会用的Lombok注解

    我见过很多反对Lombok的同学,背地里又偷偷的把插件添加了进去,这是真香原理在搞鬼.嘴上说不要,身体很诚实.反对的人,应该是没见过一些业务代码的冗长繁杂,还沉浸在自己病态的完美主义中. 要面对又脏又 ...

最新文章

  1. 句法分析常用算法框架以及NLPIR、Dependency Viwer
  2. C#/.NET基于Topshelf创建Windows服务的守护程序作为服务启动的客户端桌面程序不显示UI界面的问题分析和解决方案
  3. matlab中fminunc函数使用方法,[分享]无约束非线性规划函数\fminunc函数使用方法(MATLAB)...
  4. Java的知识点27——打印子孙级目录和文件的名称、统计文件夹的大小、编码与解码的应用
  5. 格式化输出中的%s和%S的区别
  6. Java的IO操作(二) - 带缓冲区的流对象、写入基本数据类型、实现命令行中的copy命令...
  7. 理解 Hook 规则
  8. 【leetcode】二进制手表-经典或回溯题目
  9. UEditor的使用方法
  10. BitComet(比特彗星) BT磁力链下载推荐
  11. Python用pyecharts绘制中国各地级市gdp分布点图
  12. 单车架的ANSYS有限元分析
  13. 限流10万QPS、跨域、过滤器、令牌桶算法-网关Gateway内容柒哥都给你总结在这儿了...
  14. Ubuntu 关闭guest用户
  15. 计时函数clock()与数据类型clock_t
  16. ADB有线连接车机连不上的解决方案2
  17. 响应式设计:理解设备像素,CSS像素和屏幕分辨率
  18. python 获取百度地图上北京地铁的数据,然后excel导出
  19. cnn生成图像显著图_基本原理 | 图片中的绝对位置信息,CNN能搞定吗?
  20. DropWizard的AOP扩展点最佳实践

热门文章

  1. mysql统计同一字段重复的个数
  2. Halcon学习笔记:读取多张图片
  3. PyTorch框架学习九——网络模型的构建
  4. Fast R-CNN整体把握
  5. ❤ CSDN精心打造一款插件,让你的浏览器:解锁黑科技、个性十足、沉浸式体验 ❤
  6. 《Python快速入门》基础知识扫盲课
  7. Python异步非阻塞IO多路复用Select/Poll/Epoll使用
  8. 相互引用的初始化过程
  9. 两个numpy取相同值_闲谈Numpy的切片规则
  10. 现代软件工程课件 需求分析 如何提出靠谱的项目建议 NABCD