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

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

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 RefactoryProjectEntities

dotnet ef database update

Entity 主键添加自动生成

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

启动程序,Postman 访问

32.jpg

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 为空

33.jpg

因为 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);

这样就可以查到项目信息

34.jpg

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.PhotoId
            select 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 grouping
            select 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 g
            select 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 grouping
            from 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

目录
相关文章
|
1天前
|
Kubernetes Cloud Native 持续交付
深入理解云原生技术及其在现代IT架构中的应用
【9月更文挑战第18天】云原生技术,作为推动企业数字化转型的引擎,正以它独特的魅力重塑着信息技术的未来。本文将带你一探究竟,从云原生的基础概念出发,逐步深入到其核心组件、设计理念以及如何在实际应用中发挥巨大作用。你将了解到容器化、微服务架构、持续集成与持续部署(CI/CD)等关键实践,并见证它们如何帮助企业构建更加灵活、高效和可靠的应用。
|
1天前
|
运维 Kubernetes Cloud Native
探索云原生技术:容器化与微服务架构的融合之道
【9月更文挑战第18天】在数字化转型的浪潮中,云原生技术以其灵活性、可扩展性成为企业创新的强大引擎。本文将深入探讨云原生技术的核心概念,特别是容器化和微服务架构如何相辅相成,共同推动现代应用的开发与部署。通过实际代码示例,我们将揭示这些技术如何简化运维,加速产品上市时间,并提高系统的可靠性和弹性。无论你是开发人员、架构师还是IT决策者,这篇文章都将为你提供宝贵的洞见和实践指导。
11 2
|
2天前
|
运维 Cloud Native Devops
云原生技术:重塑现代IT架构的新引擎
在当今数字化转型的浪潮中,云原生技术以其敏捷、高效和可扩展的特性,正引领着一场IT架构的革命。本文旨在深入探讨云原生的概念、核心组件及其在现代企业中的应用价值,揭示其如何助力企业实现更快的创新速度、更高的资源利用率以及更优的用户体验。不同于传统的云计算模式,云原生从一开始就为云环境量身打造,通过容器化、微服务、DevOps等关键技术,解锁了软件开发和运维的新范式。
|
4天前
|
运维 Cloud Native 持续交付
探索云原生架构:企业转型的未来之路
在当今这个数据驱动的时代,企业面临着前所未有的挑战与机遇。随着云计算技术的日益成熟,云原生作为一种新兴的架构理念,正逐步成为推动企业数字化转型的关键力量。本文旨在深入探讨云原生的概念、特点及其对企业转型的重要意义,并通过实例分析展示其在实际应用中的巨大潜力和价值。
|
7天前
|
运维 Cloud Native Devops
探索云原生架构:企业数字化转型的新引擎
在当今数字化浪潮中,云原生架构以其敏捷性、弹性和高可用性成为企业实现高效上云和加速创新的关键。本文将深入探讨云原生的核心理念、关键技术如容器化、微服务和DevOps实践,以及这些技术如何共同推动企业在云平台上的灵活部署和快速迭代。同时,文章还将分析成功案例,展示云原生如何帮助企业构建现代化应用,提高资源利用率,并确保系统稳定运行。通过综合运用这些先进技术策略,企业能够有效应对市场变化,缩短产品上市时间,从而在激烈的市场竞争中脱颖而出。
|
7天前
|
Cloud Native Devops 持续交付
探索云原生架构:构建高效、灵活和可扩展的系统
本文将深入探讨云原生架构的核心概念、主要技术以及其带来的优势。我们将从云原生的定义开始,了解其设计理念和技术原则;接着分析容器化、微服务等关键技术在云原生中的应用;最后总结云原生架构如何助力企业实现数字化转型,提升业务敏捷性和创新能力。通过这篇文章,读者可以全面了解云原生架构的价值和应用前景。
|
6天前
|
Kubernetes Cloud Native 持续交付
探秘云原生架构:企业数字化转型的新引擎
在当今数字化浪潮中,云原生架构正成为推动企业创新与灵活性的关键因素。本文将深入探讨云原生的核心理念、关键技术以及它如何助力企业实现高效运营和快速响应市场变化,为读者揭示这一现代技术趋势背后的深刻内涵与实践价值。
15 2
|
7天前
|
运维 Cloud Native Devops
云原生架构的崛起与实践云原生架构是一种通过容器化、微服务和DevOps等技术手段,帮助应用系统实现敏捷部署、弹性扩展和高效运维的技术理念。本文将探讨云原生的概念、核心技术以及其在企业中的应用实践,揭示云原生如何成为现代软件开发和运营的主流方式。##
云原生架构是现代IT领域的一场革命,它依托于容器化、微服务和DevOps等核心技术,旨在解决传统架构在应对复杂业务需求时的不足。通过采用云原生方法,企业可以实现敏捷部署、弹性扩展和高效运维,从而大幅提升开发效率和系统可靠性。本文详细阐述了云原生的核心概念、主要技术和实际应用案例,并探讨了企业在实施云原生过程中的挑战与解决方案。无论是正在转型的传统企业,还是寻求创新的互联网企业,云原生都提供了一条实现高效能、高灵活性和高可靠性的技术路径。 ##
18 3
|
11天前
|
Cloud Native 持续交付 云计算
云原生技术在现代IT架构中的革新角色
随着数字化转型的浪潮席卷全球,企业对信息技术的需求日益增长。本文将探讨云原生技术如何推动现代IT架构的创新和优化,包括容器化、微服务架构、持续集成与持续部署(CI/CD)等核心概念。通过实际案例分析,我们将了解这些技术是如何帮助企业提升灵活性、加速产品上市时间并降低运营成本的。文章旨在为读者提供云原生技术的全面视角,揭示其在现代IT战略中不可或缺的地位。
|
14天前
|
监控 Cloud Native 持续交付
云原生时代的微服务架构实践
【9月更文挑战第5天】随着云计算技术的飞速发展,云原生已成为现代软件开发的重要趋势。本文将深入探讨在云原生环境下,如何有效实施微服务架构,包括服务拆分、容器化部署、持续集成与交付等关键环节。通过具体案例,我们将展示如何在云平台上构建弹性、可扩展的微服务应用,并讨论在此过程中可能遇到的挑战及解决策略。

热门文章

最新文章