首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >.NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记

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

原创
作者头像
郑子铭
修改于 2020-12-31 08:15:54
修改于 2020-12-31 08:15:54
1.4K0
举报

2.4.5 EF Core -- 查询

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

关联数据加载

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

ProjectGroup 添加 Member 列表

代码语言:javascript
AI代码解释
复制
public List<Member> Members { get; set; }

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

代码语言:javascript
AI代码解释
复制
public bool IsAssistant { get; set; }

public string GroupId { get; set; }

public ProjectGroup Group { get; set; }

Task 添加 学员信息

代码语言:javascript
AI代码解释
复制
public Member Member { get; set; }

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

一个 Project 对应多个 ProjectGroup

ProjectGroup

代码语言:javascript
AI代码解释
复制
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);
        }
    }
}

迁移

代码语言:javascript
AI代码解释
复制
dotnet ef migrations add RefactoryProjectEntities

dotnet ef database update

Entity 主键添加自动生成

代码语言:javascript
AI代码解释
复制
/// <summary>
/// 主键Id
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }

启动程序,Postman 访问

ProjectController

代码语言:javascript
AI代码解释
复制
[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

代码语言:javascript
AI代码解释
复制
[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

代码语言:javascript
AI代码解释
复制
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 属性。

代码语言:javascript
AI代码解释
复制
using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ToList();
}

显式加载

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

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

代码语言:javascript
AI代码解释
复制
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

代码语言:javascript
AI代码解释
复制
// 显式加载
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 来启用该包。

代码语言:javascript
AI代码解释
复制
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseLazyLoadingProxies()
        .UseSqlServer(myConnectionString);

或在使用 AddDbContext 时:

代码语言:javascript
AI代码解释
复制
.AddDbContext<BloggingContext>(
    b => b.UseLazyLoadingProxies()
          .UseSqlServer(myConnectionString));

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

代码语言:javascript
AI代码解释
复制
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

代码语言:javascript
AI代码解释
复制
public virtual ICollection<ProjectGroup> Groups { get; set; }

ProjectController

代码语言:javascript
AI代码解释
复制
// 延迟加载
project.Groups// 引用到属性时才加载

客户端与服务端运算

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

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

代码语言:javascript
AI代码解释
复制
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;
}

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

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

代码语言:javascript
AI代码解释
复制
foreach (var project in _lighterDbContext.Projects)
{
    project.Groups// 多次查询数据库
}

应该一次性查询

代码语言:javascript
AI代码解释
复制
var projects = _lighterDbContext.Projects.ToList();

跟踪与不跟踪

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

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

非跟踪查询

代码语言:javascript
AI代码解释
复制
var blogs = context.Blogs
    .AsNoTracking()
    .ToList();

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

代码语言:javascript
AI代码解释
复制
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

var blogs = context.Blogs.ToList();

复杂查询运算

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

联接

代码语言:javascript
AI代码解释
复制
var query = from photo in context.Set<PersonPhoto>()
            join person in context.Set<Person>()
                on photo.PersonPhotoId equals person.PhotoId
            select new { person, photo };

GroupJoin

代码语言:javascript
AI代码解释
复制
var query = from b in context.Set<Blog>()
            join p in context.Set<Post>()
                on b.BlogId equals p.PostId into grouping
            select new { b, grouping };

SelectMany

代码语言:javascript
AI代码解释
复制
var query = from b in context.Set<Blog>()
            from p in context.Set<Post>()
            select new { b, p };

GroupBy

代码语言:javascript
AI代码解释
复制
var query = from p in context.Set<Post>()
            group p by p.AuthorId into g
            select new
            {
                g.Key,
                Count = g.Count()
            };

Left Join

代码语言:javascript
AI代码解释
复制
var query = from b in context.Set<Blog>()
            join p in context.Set<Post>()
                on b.BlogId equals p.BlogId into grouping
            from p in grouping.DefaultIfEmpty()
            select new { b, p };

原生 SQL 查询

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

代码语言:javascript
AI代码解释
复制
var blogs = context.Blogs
    .FromSqlRaw("SELECT * FROM dbo.Blogs")
    .ToList();

全局查询筛选器

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

代码语言:javascript
AI代码解释
复制
modelBuilder.Entity<Blog>().HasQueryFilter(b => EF.Property<string>(b, "_tenantId") == _tenantId);
modelBuilder.Entity<Post>().HasQueryFilter(p => !p.IsDeleted);

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

LighterDbContext

代码语言:javascript
AI代码解释
复制
modelBuilder.Entity<Entity>().HasQueryFilter(x => x.TenantId == "");

GitHub源码链接:

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 基础与配置)--学习笔记
Entity Framework Core:https://docs.microsoft.com/zh-cn/ef/core/
郑子铭
2020/12/28
1.2K0
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 基础与配置)--学习笔记
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记
乐观处理:系统认为数据的更新在大多数情况下是不会产生冲突的,只在数据库更新操作提交的时候才对数据作冲突检测(推荐)
郑子铭
2020/12/31
7210
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 关系)--学习笔记
2.4.4 EF Core -- 关系 一对多 一对一 多对多 示例 关系:https://docs.microsoft.com/zh-cn/ef/core/modeling/relationship
郑子铭
2020/12/29
7740
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 关系)--学习笔记
03-EF Core笔记之查询数据
微软提供了一百多个示例来演示查询,地址:https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
拓荒者IT
2019/09/23
3.1K0
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 介绍)--学习笔记
一个工作单元在一个事务范围内保留所有对数据库的变更,在这个工作单元结束的时候一次性提交所有改动到数据库
郑子铭
2020/12/27
1.2K0
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 介绍)--学习笔记
EF Core 性能陷阱:10个悄然扼杀应用速度的隐形杀手及破解之道
Entity Framework Core 彻底改变了 .NET 应用程序的数据访问方式,但能力越大,责任越大。尽管它拥有优雅的 API 和开发者友好的方法,但如果使用不当,EF Core 也可能成为性能瓶颈。在多年的应用程序优化和无数代码审查(Pull Request)经验中,我总结了开发者最常陷入的性能陷阱。
郑子铭
2025/09/02
3050
EF Core 性能陷阱:10个悄然扼杀应用速度的隐形杀手及破解之道
02-EF Core笔记之保存数据
EF Core通过ChangeTracker跟踪需要写入数据库的更改,当需要保存数据时,调用DbContext的SaveChanges方法完成保存。
拓荒者IT
2019/09/23
2.2K0
01-EF Core笔记之创建模型
使用EF Core的第一步是创建数据模型,模型建的好,下班走的早。EF Core本身已经设置了一系列约定来帮我们快速的创建模型,例如表名、主键字段等,毕竟约定大于配置嘛。如果你想改变默认值,很简单,EF Core提供了Fluent API或Data Annotations两种方式允许我们定制数据模型。
拓荒者IT
2019/09/23
3.7K0
.NET 云原生架构师训练营(模块二 基础巩固 MongoDB API实现)--学习笔记
https://github.com/MINGSON666/Personal-Learning-Library/tree/main/ArchitectTrainingCamp/LighterApi
郑子铭
2021/01/06
4030
.NET 云原生架构师训练营(模块二 基础巩固 MongoDB API实现)--学习笔记
.NET 云原生架构师训练营(模块二 基础巩固 MongoDB API重构)--学习笔记
将业务从controller 抽取到 Lighter.Application 层,并为业务建立抽象接口 Lighter.Application.Contract层
郑子铭
2021/01/07
5820
.NET 云原生架构师训练营(模块二 基础巩固 MongoDB API重构)--学习笔记
.NET 云原生架构师训练营(模块二 基础巩固 Host)--学习笔记
2.2.4 核心模块--Host 什么是 Host Host 的默认配置做了哪些事情 框架提供的服务 HostedService 后台服务 ASP.NET Core Web 主机:https://do
郑子铭
2021/01/13
4760
EF Core 基础知识
EF Core 默认会与 ASP.NET Core的日志提供程序一起工作,只需要使用AddDbContext或AddDbContextPool添加服务即可。
拓荒者IT
2019/09/23
9610
Entity Framework Core 2.0 入门
LearnEf.Console依赖LearnEf.Domains和LearnEf.Data:
solenovex
2018/03/12
4.1K0
Entity Framework Core 2.0 入门
C# 数据操作系列 - 8. EF Core的增删改查
到目前为止,我们看了一下如何声明EF Core的初步使用,也整体的看了下EF Core的映射关系配置以及导航属性的配置。
程序员小高
2020/05/21
3.9K0
.NET 云原生架构师训练营(模块二 基础巩固 Host)--学习笔记
2.2.4 核心模块--Host 什么是 Host Host 的默认配置做了哪些事情 框架提供的服务 HostedService 后台服务 ASP.NET Core Web 主机:https://do
郑子铭
2020/12/17
6750
.NET 云原生架构师训练营(模块二 基础巩固 Host)--学习笔记
Entity Framework Core 2.0 使用入门
一.前言 Entity Framework(后面简称EF)作为微软家的ORM,自然而然从.NET Framework延续到了.NET Core。以前我也嫌弃EF太重而不去使用它,但是EF Core(Entity Framework Core)已经做了很多性能优化,还有一些增加新特性,吸引了我去使用它。关于EF Core 2.0 的新特性请看:http://www.cnblogs.com/stulzq/p/7366044.html 二.控制台程序使用 EF Core(Code First) 1.新建一个.NE
晓晨
2018/06/22
1.5K0
.NET 云原生架构师训练营(KestrelServer源码分析)--学习笔记
理解 KestrelServer 如何接收网络请求,网络请求如何转换成 http request context(C# 可识别)
郑子铭
2022/01/17
3570
.NET 云原生架构师训练营(KestrelServer源码分析)--学习笔记
SQL语句在EFCore中的简单映射
在Entity Framework Core (EF Core)中,许多SQL语句的功能可以通过LINQ(Language Integrated Query)查询或EF Core特定的方法来实现。虽然EF Core并不直接映射SQL函数到C#函数,但它提供了丰富的API来执行类似SQL中的操作,如聚合、筛选、排序、连接等。下面是一些常用SQL操作及其在EF Core中的对应实现方式:
哇侠转转
2024/08/27
1.8K0
EntityFramework Core 学习扫盲
0. 写在前面 本篇文章虽说是入门学习,但是也不会循规蹈矩地把EF1.0版本一直到现在即将到来的EF Core 2.0版本相关的所有历史和细节完完整整还原出来。在后文中,笔者会直接进入正题,所以这篇文章仍然还是需要一定的EF ORM基础。 对于纯新手用户,不妨先去看看文末链接中一些优秀博客,笔者当初也是从这些博客起家,也从中得到了巨大的帮助。当然了,官方教程同样至关重要,笔者之前也贡献过部分EF CORE 官方文档资料(基本都是勘误,逃…),本篇文章中很多内容都是撷取自官方的英文文档和示例。 下文示例中
潘成涛
2018/01/18
10.4K0
.NET 云原生架构师训练营(模块二 基础巩固 MVC终结点)--学习笔记
2.3.4 Web API -- MVC终结点 MVC与MVVM 模型绑定 自定义模型绑定器 模型验证 返回数据处理 MVC与MVVM MVC ASP.NET Core MVC 概述:https://
郑子铭
2020/12/23
3.4K0
.NET 云原生架构师训练营(模块二 基础巩固 MVC终结点)--学习笔记
推荐阅读
相关推荐
.NET 云原生架构师训练营(模块二 基础巩固 EF Core 基础与配置)--学习笔记
更多 >
领券
社区新版编辑器体验调研
诚挚邀请您参与本次调研,分享您的真实使用感受与建议。您的反馈至关重要,感谢您的支持与参与!
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
首页
学习
活动
专区
圈层
工具
MCP广场
首页
学习
活动
专区
圈层
工具
MCP广场