I am trying to create a graphql server with standard query and mutations for any Entity I supply in a generic way i.e. I read in the configuration from somewhere, create the entities in memory and then create the graphql server.
I am currently able to create a generic type to query all the details but I don't seem to be able to create a generic dataloader to efficiently retrieve records by Id.
query GetSpecificSpeakerById {
byId(id: 1) {
name
}
}
Or
query GetSpecificSpeakerById {
a: byId(id: 1) {
name
}
b: byId(id: 2) {
name
}
}
The schema seems to generated correctly but I receive the following when executing the query:
{
"name": "ServerError",
"statusCode": 500,
"statusText": "Internal Server Error",
"bodyText": "{\"errors\":[{\"message\":\"The ID \\u00601\\u0060 has an invalid format.\"}]}"
}
I currently have the following code:
startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddPooledDbContextFactory<ApplicationDbContext>(options =>
options.UseSqlite("Data Source=conferences.db"));
var entityType = typeof(Speaker);
Type queryType = typeof(GenericQuery<>).MakeGenericType(entityType);
Type dataLoaderType = typeof(GenericrByIdDataLoader<>).MakeGenericType(entityType);
services
.AddGraphQLServer()
.AddQueryType(queryType)
.AddDataLoader<GenericrByIdDataLoader<Speaker>>();
}
GenericByIdDataLoader.cs
public class GenericrByIdDataLoader<TEntity> : BatchDataLoader<int, TEntity>
where TEntity : class, IEntity
{
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
public GenericrByIdDataLoader(
IBatchScheduler batchScheduler,
IDbContextFactory<ApplicationDbContext> dbContextFactory)
: base(batchScheduler)
{
_dbContextFactory = dbContextFactory ??
throw new ArgumentNullException(nameof(dbContextFactory));
}
protected override async Task<IReadOnlyDictionary<int, TEntity>> LoadBatchAsync(
IReadOnlyList<int> keys,
CancellationToken cancellationToken)
{
await using ApplicationDbContext dbContext =
_dbContextFactory.CreateDbContext();
return await dbContext.Set<TEntity>()
.Where(s => keys.Contains(s.Id))
.ToDictionaryAsync(t => t.Id, cancellationToken);
}
}
GenericQuery.cs
public class GenericQuery<TEntity>
where TEntity : class, IEntity
{
[UseApplicationDbContext]
public async Task<List<TEntity>> GetAll([ScopedService] ApplicationDbContext context)
{
return await context.Set<TEntity>().AsNoTracking().ToListAsync();
}
public Task<TEntity> GetByIdAsync(
[ID(nameof(TEntity))] int id,
GenericrByIdDataLoader<TEntity> dataLoader,
CancellationToken cancellationToken)
{
return dataLoader.LoadAsync(id, cancellationToken);
}
}
IEntity.cs
public interface IEntity
{
int Id { get; set; }
}
Speaker.cs
public class Speaker : IEntity
{
public int Id { get; set; }
[Required]
[StringLength(200)]
public string? Name { get; set; }
[StringLength(4000)]
public string? Bio { get; set; }
[StringLength(1000)]
public virtual string? WebSite { get; set; }
}
Any idea what the issue is?
Thanks