.NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记
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
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记相关推荐
- ef 多个左联接查询_.NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记...
2.4.5 EF Core -- 查询 关联数据加载 客户端与服务端运算 跟踪与不跟踪 复杂查询运算 原生 SQL 查询 全局查询筛选器 关联数据加载 学员和助教都在项目分组中,调整模型,删除 Ass ...
- .NET 云原生架构师训练营(模块二 基础巩固 配置)--学习笔记
2.2.3 核心模块--配置 IConfiguration Options ASP.NET Core 中的配置:https://docs.microsoft.com/zh-cn/aspnet/core ...
- .NET 云原生架构师训练营(模块二 基础巩固 日志)--学习笔记
2.2.2 核心模块--日志 ILogger 的使用 日志的 ID 日志的分类 日志的级别 LoggerProvider 日志的最佳实践 .NET Core 和 ASP.NET Core 中的日志记录 ...
- .NET 云原生架构师训练营(模块二 基础巩固 依赖注入)--学习笔记
2.2.1 核心模块--依赖注入 什么是依赖注入 .NET Core DI 生命周期 服务设计 服务范围检查 ASP.NET Core 依赖注入:https://docs.microsoft.com/ ...
- .NET 云原生架构师训练营(模块二 基础巩固 安全)--学习笔记
2.8 安全 认证 VS 授权 ASP .NET Core 认证授权中间件 认证 JWT 认证 授权 认证 VS 授权 认证是一个识别用户是谁的过程 授权是一个决定用户可以干什么的过程 401 Una ...
- .NET 云原生架构师训练营(模块二 基础巩固 REST RESTful)--学习笔记
2.3.1 Web API -- REST && RESTful 什么是 REST,什么是 RESTful RESTful API 设计 RESTful 成熟度模型 什么是 REST, ...
- .NET 云原生架构师训练营(模块二 基础巩固 引入)--学习笔记
2.1 引入 http协议 web server && web application framework .net 与 .net core asp .net core web api ...
- .NET 云原生架构师训练营(系统架构)--学习笔记
▲ 点击上方"DotNet NB"关注公众号 回复"1"获取开发者路线图 学习分享 丨作者 / 郑 子 铭 这是DotNet NB 公众号的第176篇原创文章 ...
- .NET 云原生架构师训练营(设计原则设计模式)--学习笔记
▲ 点击上方"DotNet NB"关注公众号 回复"1"获取开发者路线图 学习分享 丨作者 / 郑 子 铭 这是DotNet NB 公众号的第180篇原创文章 ...
最新文章
- SSM登陆拦截器实现
- vector删除第i个元素_[LeetCode] 215. 数组中的第K个最大元素
- Oracle 总复习
- iOS 5中的strong和weak关键字
- python中da_python学习 da4
- spring boot创建应用 端口冲突8080
- php 删除相对应的id,PHP 在下面这个留言板代码中加入删除按钮,每一个删除按钮删除相对应一行数据,这怎么弄...
- 杭电1599 find the mincost route
- c语言谭浩强ppt课件,编程_C语言学习课件_谭浩强_PPT~1216F.ppt
- excel 时间戳转换为日期
- 数据驱动型文化是大数据成功的关键
- 《JAVA语言程序设计与数据结构》(基础篇)原书第11版 第一章(答案)
- php拾取当前经纬度,获取中国各省市区县经纬度的方法
- 奇舞周刊第 444 期:浅谈文档的实时协同编辑
- Unity Application Block 1.0系列(5): 使用BuildUp让已存在对象实例也支持依赖注入
- 金融风控领域算法比赛经验分享——翼支付杯大数据建模大赛-季军方案
- python-Selenium
- blender bpy
- python区域找图_使用Imagemagick查找相似区域
- TNF 又见 《Cell》