系列导航

使用Hot Chocolate和.NET 6构建GraphQL应用文章索引

需求

在上一篇文章使用Hot Chocolate和.NET 6构建GraphQL应用(3) —— 实现Query基础功能中,我们留了两个问题,一是通过GraphQL接口返回的Posts结果并没有获取到关联的Comment和Tag内容,二是返回结果没有进行排序。在这篇文章中,我们先来解决第一个问题。

思路

要获取关联实体,使用EF Core自然会想到在进行Query的时候添加一下Include语句就可以了,这种方式虽然可以实现,但是这其实并不太符合GraphQL接口的风格。GraphQL本身就是将数据对象作为图中的顶点以及其邻接点来看待的。所以我们不会修改接口本身的逻辑,通过Hot Chocolate为我们提供的映射(Projection)属性来完成需求。

实现

要使用Projection属性,需要先在添加服务依赖注入的时候指定:

  • ProgramExtension.cs
builder.Services
    .AddGraphQLServer()
    .AddProjections()
    .AddQueryType<Query>()
    .AddType<PostType>();

然后在接口上方添加UseProjection即可:

  • Query.cs
[UseProjection]
public IQueryable<Post> GetPosts([Service] IRepository<Post> repository) => repository.GetAsQueryable();

这样就实现了关联实体的获取,非常简单,下面我们来验证一下。

验证

启动Api项目,调用接口:

可以看到Comment和Tag信息已经出现在返回体中了,我们再来看一下控制台输出的EF Core日志:

[09:48:40 INF] Executing endpoint 'Hot Chocolate GraphQL Pipeline'
[09:48:40 WRN] Compiling a query which loads related collections for more than one collection navigation, either via 'Include' or through projection, but no 'QuerySplittingBehavior' has been configured. By default, Entity Framework will use 'QuerySplittingBehavior.SingleQuery', which can potentially result in slow query performance. See https://go.microsoft.com/fwlink/?linkid=2134277 for more information. To identify the query that's triggering this warning call 'ConfigureWarnings(w => w.Throw(RelationalEventId.MultipleCollectionIncludeWarning))'.
[09:48:40 INF] Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT "p"."Id", "p"."Title", "p"."Author", "c"."Content", "c"."Id", "t0"."Name", "t0"."PostsId", "t0"."TagsId", "t0"."Id"
FROM "Posts" AS "p"
LEFT JOIN "Comments" AS "c" ON "p"."Id" = "c"."PostId"
LEFT JOIN (
    SELECT "t"."Name", "p0"."PostsId", "p0"."TagsId", "t"."Id"
    FROM "PostTag" AS "p0"
    INNER JOIN "Tags" AS "t" ON "p0"."TagsId" = "t"."Id"
) AS "t0" ON "p"."Id" = "t0"."PostsId"
ORDER BY "p"."Id", "c"."Id", "t0"."PostsId", "t0"."TagsId"
[09:48:40 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'

从日志中可以看到Hot Chocolate告诉我们加载多个关联实体集合的时候要么通过Include方式,要么使用Projection,但是在没有应用任何QuerySplittingBehavior的情况下,会默认使用QuerySplittingBehavior.SingleQuery方式,可能会导致慢查询,具体的说明也给出了链接,有兴趣的小伙伴可以看一下。

然后就是实际执行的SQL语句了,可以看到这次的SQL语句明显进行了关联对象之间的Join操作,所以能得到我们希望的结果。

总结

在本文中我们实现了关联对象的获取,下一篇文章将会介绍如何进行查询数据的过滤。