graphql - 如何使用 DataLoader 与 Hot Chocolate GraphQL 进行连接
问题描述
我看到可以将数据加载器用于根查询,但也可以将数据加载器用于嵌套连接吗?在下面的示例中,我想为属性使用数据加载器rooms
。在底部的示例请求中,将进行三个数据库查询。一个由数据加载器获取两座建筑物,一个获取建筑物 1 的房间,另一个获取建筑物 2 的房间。相反,我试图为房间使用数据加载器,因此只有两个数据库查询制成。
// Building DB table
ID | Name
1 | Main Campus
2 | Satellite Campus
// Rooms DB table
ID | BuildingId | Name
1 | 1 | Lab
2 | 1 | Dorm
3 | 2 | Theatre
4 | 2 | Gym
// Schema
type Building {
id: Int!
name: String!
rooms(after: String before: String first: PaginationAmount last: PaginationAmount): RoomsConnection
}
type Room {
id: Int!
name: String!
building: Building!
}
// Hot Chocolate
public class BuildingType: ObjectType<Building> {
protected override void Configure(IObjectTypeDescriptor<Building> descriptor)
{
// ... omitted other fields for brevity
// Instead of using a resolver, can a data loader be used instead?
descriptor.Field(b => b.rooms).UsePaging<RoomType>().Resolver(ctx => {
var building = ctx.Parent<Building>();
var roomsRepository = ctx.Service<IRoomsRepository>();
return roomsRepository.GetRoomsByBuildingId(building.Id);
});
}
}
// Example request
query {
a: building(id: 1){
id,
name,
rooms {
nodes {
id,
name
}
}
},
b: building(id: 2){
id,
name,
rooms {
nodes {
id,
name
}
}
}
}
解决方案
这不仅是可能的,而且我会说这是 DataLoaders 避免跨对象树发出“N+1”请求的基本用例。出于您的目的,您可以使用GroupDataLoader。组数据加载器是一个批量数据加载器,即它收集在一次 graphql 请求往返中对类似实体的请求,并将它们作为单个请求发送到数据源。之后,它会缓存结果——即当从对象树的任何位置请求时从缓存中返回实体。组数据加载器获取键列表作为输入参数 (IReadOnlyList<TKey>) 并返回缓存实体列表作为查找 (ILookup<TKey, TValue>)。查找是一种每个键保存多个值的数据类型(而不是每个键保存单个值的字典)。
根据您的具体情况,必须按建筑物 ID 对房间进行分组——这是关键。因此,您可以通过以下方式使用组数据加载器来缓存您的连接(考虑到更改 RoomsRepository 的接口以支持对它的批量请求是值得的,即它必须接受的不是单个建筑物 ID,而是其中一批,我还假设 Room 包含对其建筑 ID 的反向引用):
public class BuildingType : ObjectType<Building>
{
protected override void Configure(IObjectTypeDescriptor<Building> descriptor)
{
descriptor.Field(b => h.rooms).UsePaging<RoomType>
.Resolver(async (ctx, t) => await ctx.GroupDataLoader<int, Room>("roomsByBuildingGroup",
async keys => ctx.Service<IRoomsRepository>().GetRoomsByBuildingIds(keys).ToLookup(r => r.BuildingId))
.LoadAsync(ctx.Parent<Building>().Id, t));
}
“roomsByBuildingGroup”是加载程序的名称。为了共享一个缓存并将来自不同对象树位置的所有请求组合成一个,您必须在通过构建 id 加载房间的所有其他位置使用相同的加载器(即使用相同的加载器名称)。
推荐阅读
- api - Flutter中如何通过API发送数据?
- python - 扩展和填充 Pandas DataFrame 以匹配另一个
- c# - 如何应用检查仅选择简单字符串并忽略包含日期的字符串?
- solr - 我如何将 NLP 与 solr 集成以进行 NLP 搜索
- java - 复制`ArrayList是否安全
`以这种方式? - android - 突出显示文本视图中的搜索文本不起作用
- python - pd.read_csv 一个 750 MB 的文本文件
- c - C 输入 2 次并检查之前的值
- snowflake-cloud-data-platform - 微分区和数据集群有什么区别
- bash - bash 当你找到两列时删除 bash 中的第一列