如何使用DataLoader连接热巧克力GraphQL
我看到可以对根查询使用数据加载器,但对嵌套连接也可以使用数据加载器吗?在下面的示例中,我希望为如何使用DataLoader连接热巧克力GraphQL,graphql,dataloader,hotchocolate,Graphql,Dataloader,Hotchocolate,我看到可以对根查询使用数据加载器,但对嵌套连接也可以使用数据加载器吗?在下面的示例中,我希望为rooms属性使用数据加载器。在底部的示例请求中,将进行三次数据库查询。一个由数据加载器获取两座建筑物,一个为1号楼获取房间,另一个为2号楼获取房间。相反,我尝试为房间使用数据加载器,因此只进行两次数据库查询 // Building DB table ID | Name 1 | Main Campus 2 | Satellite Campus 这不仅是可能的,而且我认为这是数据加载程序避免跨对象树
rooms
属性使用数据加载器。在底部的示例请求中,将进行三次数据库查询。一个由数据加载器获取两座建筑物,一个为1号楼获取房间,另一个为2号楼获取房间。相反,我尝试为房间使用数据加载器,因此只进行两次数据库查询
// Building DB table
ID | Name
1 | Main Campus
2 | Satellite Campus
这不仅是可能的,而且我认为这是数据加载程序避免跨对象树发出“N+1”请求的基本用例。 为了你的目的,你可以使用。组数据加载器是一个批处理数据加载器,即它收集在一个graphql请求往返中对类似实体的请求,并将它们作为单个请求发送到数据源。之后,它缓存结果,即从对象树的任何位置请求时从缓存返回实体。组数据加载器获取键列表作为输入参数(IReadOnlyList),并返回缓存实体列表作为查找(ILookup)。Lookup是一种数据类型,每个键包含多个值(而不是字典,每个键只包含一个值) 根据您的具体情况,房间必须按建筑id进行分组-这是关键。因此,您可以使用组数据加载器以以下方式缓存连接(考虑到更改RoomsRepository的接口以支持对它的批处理请求是值得的,即它必须接受一个建筑id,而不是一个建筑id,我还假设房间包含对其建筑id的反向引用):
公共类BuildingType:ObjectType
{
受保护的覆盖无效配置(IObjectTypeDescriptor描述符)
{
descriptor.Field(b=>h.rooms).UsePaging
.Resolver(异步(ctx,t)=>等待ctx.GroupDataLoader(“roomsByBuildingGroup”,
异步键=>ctx.Service().GetRoomsByBuildingId(键).ToLookup(r=>r.BuildingId))
.LoadAsync(ctx.Parent().Id,t));
}
“roomsByBuildingGroup”是加载程序的名称。为了共享缓存并将来自不同对象树位置的所有请求合并为一个请求,您必须在通过建筑id加载房间的所有其他位置使用相同的加载程序(即使用相同的加载程序名称)
// 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
}
}
}
}
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));