1

使用 HotChocolate 版本:10.5.5

并给出以下Customer域模型:

public class Customer
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CustomerID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string CompanyName { get; set; }
    public string SalesPerson { get; set; }
}

Customers在查询界面中公开实体框架数据库集时:

[UseSelection]
[UseFiltering]
public IQueryable<Customer> GetCustomers([Service] AdventureWorksContext ctx) => ctx.Customers;

并执行以下 graphql 查询:

query {
  friendlyBikeShop: customers (where: { companyName: "Friendly Bike Shop"}){
    firstName,
    lastName
  },
  frontSportingGoods: customers (where: { companyName: "Front Sporting Goods"}){
    firstName,
    lastName
  }
}

产生以下两条 SQL 语句:

SELECT [c].[FirstName], [c].[LastName]
FROM [SalesLT].[Customer] AS [c]
WHERE [c].[CompanyName] = N'Front Sporting Goods'

SELECT [c].[FirstName], [c].[LastName]
FROM [SalesLT].[Customer] AS [c]
WHERE [c].[CompanyName] = N'Front Sporting Goods'

这并不理想,因为我想将其合并到一个 SQL 语句中:

SELECT [c].[FirstName], [c].[LastName]
FROM [SalesLT].[Customer] AS [c]
WHERE [c].[CompanyName] in (N'Front Sporting Goods', N'Front Sporting Goods')

使用 a 解决此问题的第一次尝试GroupDataLoader如下:

[UseSelection]
[UseFiltering]
public Task<Customer[]> GetCustomersByCompanyName(IResolverContext resolverCtx, [Service] AdventureWorksContext ctx, string companyName) =>
    resolverCtx.GroupDataLoader<string, Customer>("customers", async keys =>
    {
        var customers = await ctx.Customers.Where(customer => keys.Any(key => key == customer.CompanyName)).ToListAsync();
        return customers.ToLookup(customer => customer.CompanyName);
    }).LoadAsync(companyName, default);

并执行以下graphql:

query {
  friendlyBikeShop: customersByCompanyName(companyName: "Friendly Bike Shop"){
    firstName,
    lastName
  },
  frontSportingGoods: customersByCompanyName(companyName: "Front Sporting Goods"){
    firstName,
    lastName
  }
}

生成以下单个 SQL 语句:

SELECT [c].[CustomerID], [c].[CompanyName], [c].[FirstName], [c].[LastName], [c].[SalesPerson]
FROM [SalesLT].[Customer] AS [c]
WHERE [c].[CompanyName] IN (N'Friendly Bike Shop', N'Front Sporting Goods')

这种方法的缺点是Filtering并且Selection没有考虑到由 EF 生成的动态创建的 SQL 语句中,这仅在结果集从数据库返回之后应用。

如何IQueryable在查询接口上返回一个,以便中间件应用FilteringSelection考虑到动态生成的 SQL 语句中,并且仍然强制它在单个批处理中执行?

4

1 回答 1

1

HotChocolate 的数据 API 和 Dataloaders 不能很好地协同工作。这是两种不同的方法,不能在同一个解析器中混合使用。

过滤工作在解析器级别,而数据加载器确实在解析器执行之外运行。

此查询包含两个解析器:

query {
  friendlyBikeShop: customers (where: { companyName: "Friendly Bike Shop"}){
    firstName
    lastName
  }
  frontSportingGoods: customers (where: { companyName: "Front Sporting Goods"}){
    firstName
    lastName
  }
}

因此,您可以使用过滤和投影以及两个查询,也可以使用数据加载器并且只执行一个查询。

作为替代查询,您也可以这样做:

query {
  customers (
    where: { 
        companyName_in: [
            "Friendly Bike Shop",
            "Front Sporting Goods"
      ]
  }){
    firstName
    lastName
  }
}

这将在一个请求中返回两个结果

于 2021-01-17T17:50:54.893 回答