在 GraphQL dotnet 中手动解析参数以进行查询优化的最佳模式
Best pattern to manually parse arguments for query optimisation in GraphQL dotnet
我们有一个 GraphQL dotnet 实现,位于我们现有的应用程序数据库之上。
<PackageReference Include="GraphQL" Version="3.3.2" />
<PackageReference Include="GraphQL.SystemTextJson" Version="3.3.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Transports.WebSockets" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Ui.Playground" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Authorization.AspNetCore" Version="4.4.1" />
我们有一个相当复杂的数据结构,因此当从我们的一些顶级字段(包括它们的一些子字段)进行查询时,我们可能会加入大量表。但是,并非每个查询都需要所有这些连接。
我希望能够在我们的查询 ObjectGraphType 中手动解析 context.Arguments,当我解析它以在未查询特定子字段时消除连接。
一个非常简单的高级版本如下:
Field<ListGraphType<OrganisationType>>(
"organisations",
resolve: context =>
{
var retVal = database.Organisations();
//Are we joining on employers?
if(context.SubFields.ContainsKey("employers"))
{
retVal.Include(x => x.Employers.Where(x => x.Deleted != true))
.ThenInclude(x => x.Departments.Where(x => x.Deleted != true));
}
return retVal;
}
如果用户查询过,我们只加入雇主。然而,问题是雇主可以有部门、员工、经理等......而这些人本身可以有大量的子属性。
目前,我们的查询几乎加入了查询的每个排列,产生了一个非常庞大的 SQL 查询。如果用户只需要组织名称和每个雇主的名称,这将是一项繁重的工作。
在最顶层进行过滤很容易(如上所示),但我无法弄清楚如何从那一点开始查询,我似乎只是陷入了无限循环的儿童......因为示例:
var employerSubField = context.SubFields["employers"];
var otherJoins = employerSubField.SelectionSet.Children.Where(x => x.Children)
我似乎找不到 where name == "Employees" 或类似的东西。我是否需要在某个时候将 GraphQL.Language.AST.INode 转换为某些内容?当我在调试时检查这些值时,看起来我应该能够看到我所追求的值。但这不会编译。
var deptsField = employerSubField.SelectionSet.Selections.Where(x => x.Name == "departments");
我找到了以下方法来获取基本信息,然后我可以轻松地解析自己并添加自己的自定义逻辑。
var query = context.Document.OriginalQuery.Substring(context.Document.OriginalQuery.IndexOf("{")).RemoveWhitespace();
returns:
{organisations{id,name,employers{id,name,clientNotes,departments{id,name}}}}
我们有一个 GraphQL dotnet 实现,位于我们现有的应用程序数据库之上。
<PackageReference Include="GraphQL" Version="3.3.2" />
<PackageReference Include="GraphQL.SystemTextJson" Version="3.3.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Transports.WebSockets" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Ui.Playground" Version="4.4.1" />
<PackageReference Include="GraphQL.Server.Authorization.AspNetCore" Version="4.4.1" />
我们有一个相当复杂的数据结构,因此当从我们的一些顶级字段(包括它们的一些子字段)进行查询时,我们可能会加入大量表。但是,并非每个查询都需要所有这些连接。
我希望能够在我们的查询 ObjectGraphType 中手动解析 context.Arguments,当我解析它以在未查询特定子字段时消除连接。
一个非常简单的高级版本如下:
Field<ListGraphType<OrganisationType>>(
"organisations",
resolve: context =>
{
var retVal = database.Organisations();
//Are we joining on employers?
if(context.SubFields.ContainsKey("employers"))
{
retVal.Include(x => x.Employers.Where(x => x.Deleted != true))
.ThenInclude(x => x.Departments.Where(x => x.Deleted != true));
}
return retVal;
}
如果用户查询过,我们只加入雇主。然而,问题是雇主可以有部门、员工、经理等......而这些人本身可以有大量的子属性。
目前,我们的查询几乎加入了查询的每个排列,产生了一个非常庞大的 SQL 查询。如果用户只需要组织名称和每个雇主的名称,这将是一项繁重的工作。
在最顶层进行过滤很容易(如上所示),但我无法弄清楚如何从那一点开始查询,我似乎只是陷入了无限循环的儿童......因为示例:
var employerSubField = context.SubFields["employers"];
var otherJoins = employerSubField.SelectionSet.Children.Where(x => x.Children)
我似乎找不到 where name == "Employees" 或类似的东西。我是否需要在某个时候将 GraphQL.Language.AST.INode 转换为某些内容?当我在调试时检查这些值时,看起来我应该能够看到我所追求的值。但这不会编译。
var deptsField = employerSubField.SelectionSet.Selections.Where(x => x.Name == "departments");
我找到了以下方法来获取基本信息,然后我可以轻松地解析自己并添加自己的自定义逻辑。
var query = context.Document.OriginalQuery.Substring(context.Document.OriginalQuery.IndexOf("{")).RemoveWhitespace();
returns:
{organisations{id,name,employers{id,name,clientNotes,departments{id,name}}}}