I am new to graphql and am currently working through the ChilliCream graphql workshop. After implementing paging after following this
There is a note: "There is one caveat in our implementation with the TrackType. Since, we are using a DataLoader within our resolver and first fetch the list of IDs we essentially will always fetch everything and and chop in memory. In an actual project this can be split into two actions by moving the DataLoader part into a middleware and first page on the id queryable. Also one could implement a special IPagingHandler that uses the DataLoader and applies paging logic."
I have not been able to figure out how to split the two actions. Any help would be appreciated.
Query
query GetTrackWithSessions {
trackById(id: "VHJhY2sKaTE=") {
id
sessions(first: 1) {
nodes {
title
}
}
}
}
TrackQuery
public Task<Track> GetTrackByIdAsync(
[ID(nameof(Track))] int id,
TrackByIdDataLoader trackById,
CancellationToken cancellationToken) =>
trackById.LoadAsync(id, cancellationToken);
TrackType
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);
}
}
}
DataLoader
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);
}
}
Thanks