ASP.NET Core中使用GraphQL - 目录

  • ASP.NET Core中使用GraphQL - 第一章 Hello World
  • ASP.NET Core中使用GraphQL - 第二章 中间件
  • ASP.NET Core中使用GraphQL - 第三章 依赖注入
  • ASP.NET Core中使用GraphQL - 第四章 GrahpiQL
  • ASP.NET Core中使用GraphQL - 第五章 字段, 参数, 变量
  • ASP.NET Core中使用GraphQL - 第六章 使用EF Core作为持久化仓储
  • ASP.NET Core中使用GraphQL - 第七章 Mutation
  • ASP.NET Core中使用GraphQL - 第八章 在GraphQL中处理一对多关系
  • ASP.NET Core中使用GraphQL - 第九章 在GraphQL中处理多对多关系

在之前的几章中,我们的GraphQL查询是没有优化过的。下面我们以CustomerType中的orders查询为例

CustomerType.cs
Field<ListGraphType<OrderType>, IEnumerable<Order>>()  .Name("Orders").ResolveAsync(ctx =>{return dataStore.GetOrdersAsync();}); 

在这个查询中,我们获取了某个顾客中所有的订单, 这里如果你只是获取一些标量字段,那很简单。

但是如果需要获取一些关联属性呢?例如查询系统中的所有订单,在订单信息中附带顾客信息。

OrderType
public OrderType(IDataStore dataStore, IDataLoaderContextAccessor accessor)
{Field(o => o.Tag);Field(o => o.CreatedAt);Field<CustomerType, Customer>().Name("Customer").ResolveAsync(ctx =>{            return dataStore.GetCustomerByIdAsync(ctx.Source.CustomerId);  });
}

这里当获取customer信息的时候,系统会另外初始化一个请求,以便从数据仓储中查询订单相关的顾客信息。

如果你了解dotnet cli, 你可以针对以下查询,在控制台输出所有的EF查询日志

{orders{tagcreatedAtcustomer{namebillingAddress}}
}

查询结果:

{"data": {"orders": [{"tag": "XPS 13","createdAt": "2018-11-11","customer": {"name": "Lamond Lu","billingAddress": "Test Address"}},{"tag": "XPS 15","createdAt": "2018-11-11","customer": {"name": "Lamond Lu","billingAddress": "Test Address"}}]}
}

产生日志如下:

info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (16ms) [Parameters=[], CommandType='Text', CommandTimeout='30']SELECT [o].[OrderId], [o].[CreatedAt], [o].[CustomerId], [o].[CustomerId1], [o].[Tag]FROM [Orders] AS [o]
info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (6ms) [Parameters=[@__get_Item_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']SELECT TOP(1) [e].[CustomerId], [e].[BillingAddress], [e].[Name]FROM [Customers] AS [e]WHERE [e].[CustomerId] = @__get_Item_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (5ms) [Parameters=[@__get_Item_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']SELECT TOP(1) [e].[CustomerId], [e].[BillingAddress], [e].[Name]FROM [Customers] AS [e]WHERE [e].[CustomerId] = @__get_Item_0
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]Request finished in 864.2749ms 200

从日志上我们很清楚的看到,这个查询使用了3个查询语句,第一个语句查询所有的订单信息,第二个和第三个请求分别查询了2个订单的顾客信息。这里可以想象如果这里有N的订单,就会产生N+1个查询语句,这是非常不效率的。正常情况下我们其实可以通过2条语句就完成上述的查询,后面查询单个顾客信息其实可以整合成一条语句。

为了实现这个效果,我们就需要介绍一下GraphQL中的DataLoader

DataLoaderGraphQL中的一个重要功能,它为GraphtQL查询提供了批处理和缓存的功能。

为了使用DataLoader, 我们首先需要在Startup.cs中注册2个新服务IDataLoaderContextAccessorDataLoaderDocumentListener

Startup.cs
services.AddSingleton<IDataLoaderContextAccessor, DataLoaderContextAccessor>();
services.AddSingleton<DataLoaderDocumentListener>();  

如果你的某个GraphQL类型需要DataLoader, 你就可以在其构造函数中注入一个IDataLoaderContextAccessor接口对象。

但是为了使用DataLoader, 我们还需要将它添加到我们的中间件中。

GraphQLMiddleware.cs
public async Task InvokeAsync(HttpContext httpContext, ISchema schema, IServiceProvider serviceProvider)
{........var result = await _executor.ExecuteAsync(doc =>{........doc.Listeners.Add(serviceProvider                                                             .GetRequiredService<DataLoaderDocumentListener>());}).ConfigureAwait(false);........
}

下一步,我们需要为我们的仓储类,添加一个新方法,这个方法可以根据顾客的id列表,返回所有的顾客信息。

DataStore.cs
public async Task<Dictionary<int, Customer>> GetCustomersByIdAsync(IEnumerable<int> customerIds,CancellationToken token)
{return await _context.Customers.Where(i => customerIds.Contains(i.CustomerId)).ToDictionaryAsync(x => x.CustomerId);
}

然后我们修改OrderType

OrderType
Field<CustomerType, Customer>()  .Name("Customer").ResolveAsync(ctx =>{            var customersLoader = accessor.Context.GetOrAddBatchLoader<int, Customer>("GetCustomersById", dataStore.GetCustomersByIdAsync);return customersLoader.LoadAsync(ctx.Source.CustomerId);  });

完成以上修改之后,我们重新运行项目, 使用相同的query, 结果如下,查询语句的数量变成了2个,效率大大提高

info: Microsoft.EntityFrameworkCore.Infrastructure[10403]Entity Framework Core 2.1.4-rtm-31024 initialized 'ApplicationDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None
info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (19ms) [Parameters=[], CommandType='Text', CommandTimeout='30']SELECT [o].[OrderId], [o].[CreatedAt], [o].[CustomerId], [o].[CustomerId1], [o].[Tag]FROM [Orders] AS [o]
info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30']SELECT [i].[CustomerId], [i].[BillingAddress], [i].[Name]FROM [Customers] AS [i]WHERE [i].[CustomerId] IN (1)

DataLoader背后的原理

GetOrAddBatchLoader方法会等到所有查询的顾客id列表准备好之后才会执行,它会一次性把所有查询id的顾客信息都收集起来。 这种技术就叫做批处理,使用了这种技术之后,无论有多少个关联的顾客信息,系统都只会发出一次请求来获取所有数据。

本文源代码: https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20X

转载于:https://www.cnblogs.com/lwqlun/p/9972233.html

ASP.NET Core中使用GraphQL - 最终章 Data Loader相关推荐

  1. ASP.NET Core中使用GraphQL - 第一章 Hello World

    前言 你是否已经厌倦了REST风格的API? 让我们来聊一下GraphQL. GraphQL提供了一种声明式的方式从服务器拉取数据.你可以从GraphQL官网中了解到GraphQL的所有优点.在这一系 ...

  2. ASP.NET Core中使用GraphQL - 第二章 中间件

    前文:ASP.NET Core中使用GraphQL - 第一章 Hello World 中间件 如果你熟悉ASP.NET Core的中间件,你可能会注意到之前的博客中我们已经使用了一个中间件, 这个中 ...

  3. ASP.NET Core中使用GraphQL - 第七章 Mutation

    ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...

  4. ASP.NET Core中使用GraphQL - 第三章 依赖注入

    ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 SOL ...

  5. 如何使用C#在ASP.NET Core中轻松实现QRCoder

    by Yogi 由瑜伽士 如何使用C#在ASP.NET Core中轻松实现QRCoder (How to easily implement QRCoder in ASP.NET Core using ...

  6. 如何简单的在 ASP.NET Core 中集成 JWT 认证?

    前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...

  7. .ASP NET Core中缓存问题案例

    本篇博客中,我将描述一个关于会话状态(Session State)的问题, 这个问题我已经被询问了好几次了. 问题的场景 创建一个新的ASP.NET Core应用程序 一个用户在会话状态中设置了一个字 ...

  8. ASP.NET Core 中是否有 PostAsJsonAsync() 方法?

    咨询区 LP13 在 Asp.NET 中我一般都用 PostAsJsonAsync() 做数据提交,在 Asp.NET Core 时代我貌似没有找到,按照程序集的命名规范,我觉得应该也是由 Micro ...

  9. 使用Redis Stream来做消息队列和在Asp.Net Core中的实现

    Redis - Wikipedia 写在前面 我一直以来使用redis的时候,很多低烈度需求(并发要求不是很高)需要用到消息队列的时候,在项目本身已经使用了Redis的情况下都想直接用Redis来做消 ...

最新文章

  1. ubuntu系统中import h5py, ImportError: No module named h5py的解决方法
  2. 【计算机网络实验·北航】实验一:网络实验入门(1)
  3. javascript正则表达式入门
  4. python整数分节输出_pyfactor
  5. FileSystemObject 对象
  6. .Net: C#中的委托(Delegate)和事件(Event)
  7. 换了路由器电脑都连不上网了_高校连上网自由都实现不了?三大运营商:这锅我不背...
  8. 74系列相关芯片说明
  9. Non-managed pom.xml file found
  10. CAD2006提示没有足够的权限来安装此产品
  11. Nginx 重定向 80 到443
  12. flutter 屏幕截图,超出屏幕部分截图
  13. 【运维面试】面试官: 你每天在公司都做啥?
  14. 江苏省高校,中专校职称计算机信息技术应用能力考核,江苏省高校中专校专业技术人员职称信息技术应用能力考核资料.doc...
  15. android 项目导入另一个Android项目作为子模块调用
  16. 聊天机器人系统的组成结构及关键技术
  17. 自嗨模式计算机,关于自嗨模式的说说
  18. 使用Python和地图api进行地图数据采集
  19. MySQL必知必会pdf网盘下载+每章总结
  20. 《Android 开发艺术探索》笔记2--IPC机制

热门文章

  1. python 支付宝营销活动现金红包开发接入流程-含接口调用加签
  2. ArcGIS栅格波段理解
  3. ksh和bash区别
  4. GOOGLE搜索从入门到精通v3.0 from:http://www.being.org.cn/tool/google.htm
  5. noip提高组初赛有感——
  6. CAD中字体相关解析 \fsimhei|b0|i0|c134
  7. Window系统上自制快速关机脚本
  8. java ganymed ssh2_Ganymed SSH-2 for Java学习笔记
  9. 计算机应用能力 上机操作,全国职称计算机考试(专业技术人员计算机应用能力考试)Word2003中文字处理模块上机考试操作题...
  10. 怎么用计算机圣诞节快乐,圣诞节英文是什么 圣诞节快乐英文怎么写?