我是 graphql 的新手,目前正在参加 ChilliCream graphql 研讨会。在遵循此之后实施分页后
有一个注释:“在我们的 TrackType 实现中有一个警告。因为,我们在解析器中使用 DataLoader 并首先获取 ID 列表,我们基本上总是会获取所有内容并切入内存。在实际项目中通过将 DataLoader 部分移动到中间件和可查询 id 上的第一页,这可以分为两个动作。也可以实现一个特殊的 IPagingHandler,它使用 DataLoader 并应用分页逻辑。
我一直无法弄清楚如何拆分这两个动作。任何帮助,将不胜感激。
询问
query GetTrackWithSessions {
trackById(id: "VHJhY2sKaTE=") {
id
sessions(first: 1) {
nodes {
title
}
}
}
}
跟踪查询
public Task<Track> GetTrackByIdAsync(
[ID(nameof(Track))] int id,
TrackByIdDataLoader trackById,
CancellationToken cancellationToken) =>
trackById.LoadAsync(id, cancellationToken);
轨道类型
public class TrackType : ObjectType<Track>
{
protected override void Configure(IObjectTypeDescriptor<Track> descriptor)
{
descriptor
.ImplementsNode()
.IdField(t => t.Id)
.ResolveNode((ctx, id) =>
ctx.DataLoader<TrackByIdDataLoader>().LoadAsync(id, ctx.RequestAborted));
descriptor
.Field(t => t.Sessions)
.ResolveWith<TrackResolvers>(t => t.GetSessionsAsync(default!, default!, default!, default))
.UseDbContext<ApplicationDbContext>()
.UsePaging<NonNullType<SessionType>>()
.Name("sessions");
descriptor
.Field(t => t.Name)
.UseUpperCase();
}
private class TrackResolvers
{
public async Task<IEnumerable<Session>> GetSessionsAsync(
Track track,
[ScopedService] ApplicationDbContext dbContext,
SessionByIdDataLoader sessionById,
CancellationToken cancellationToken)
{
int[] sessionIds = await dbContext.Sessions
.Where(s => s.Id == track.Id)
.Select(s => s.Id)
.ToArrayAsync();
return await sessionById.LoadAsync(sessionIds, cancellationToken);
}
}
}
数据加载器
public class TrackByIdDataLoader : BatchDataLoader<int, Track>
{
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
public TrackByIdDataLoader(
IBatchScheduler batchScheduler,
IDbContextFactory<ApplicationDbContext> dbContextFactory)
: base(batchScheduler)
{
_dbContextFactory = dbContextFactory ??
throw new ArgumentNullException(nameof(dbContextFactory));
}
protected override async Task<IReadOnlyDictionary<int, Track>> LoadBatchAsync(
IReadOnlyList<int> keys,
CancellationToken cancellationToken)
{
await using ApplicationDbContext dbContext =
_dbContextFactory.CreateDbContext();
*All the tracks are returned here
return await dbContext.Tracks
.Where(s => keys.Contains(s.Id))
.ToDictionaryAsync(t => t.Id, cancellationToken);
}
}
谢谢