Per my understanding, when I use DataLoader
in GraphQL
, it should hit DB
once only with supplied key(s). This is regardless of the number of parallel calls.
What am I doing wrong here?
My scenarios:
- If I make 4 parallel calls with one ID then it is calling DB just once, so this is
GOOD. Here is my query:
query {
getExpA: exceptions(stockNumber: 2002250416) {
location
},
getExpB: exceptions(stockNumber: 2002250416) {
vin
},
getExpC: exceptions(stockNumber: 2002250416) {
createdBy
},
getExpD: exceptions(stockNumber: 2002250416) {
updatedBy
},
}
- If I change ID in 2 out of these 4 calls, then I am seeing 2 calls, which is NOT right. Here is my query:
query {
getExpA: exceptions(stockNumber: 2002250416) {
location
},
getExpB: exceptions(stockNumber: 2002250416) {
vin
},
getExpC: exceptions(stockNumber: 1112250416) {
createdBy
},
getExpD: exceptions(stockNumber: 1112250416) {
updatedBy
},
}
Query.cs
public class ExceptionsQuery
{
[Authorize(policy: "ProjectXAccess")]
public async Task<Exception> GetExceptionsAsync(
long stockNumber,
[Service(ServiceKind.Synchronized)] IExceptionService exceptionService
)
{
var result = await exceptionService.GetExceptionsByStockNumberV2(
stockNumber,
CancellationToken.None
);
return result;
}
}
Service.cs
namespace Services
{
public interface IExceptionService
{
Task<Database.Entities.Sql.Exception> GetExceptionsByStockNumberV2(
long stockNumber,
CancellationToken cancellationToken);
}
public class ExceptionService: ServiceBase, IExceptionService
{
private readonly ExceptionDataLoader _exceptionDataLoader;
public ExceptionService(
ExceptionDataLoader exceptionDataLoader
)
{
_exceptionDataLoader = exceptionDataLoader;
}
#region DATA LOADER
public Task<Database.Entities.Sql.Exception> GetExceptionsByStockNumberV2(
long stockNumber,
CancellationToken cancellationToken)
{
var result = _exceptionDataLoader.LoadAsync(stockNumber, cancellationToken);
return result;
}
#endregion DATA LOADER
}
}
DataLoader.cs
namespace DataLoaders;
public class ExceptionDataLoader : BatchDataLoader<long, Exception>
{
private readonly IDbContextFactory<AppDbContext> _dbContext;
public ExceptionDataLoader(
IDbContextFactory<AppDbContext> dbContext,
IBatchScheduler batchScheduler,
DataLoaderOptions options = null)
: base(batchScheduler, options)
{
_dbContext =
dbContext ?? throw new ArgumentNullException(nameof(dbContext));
}
protected override async Task<IReadOnlyDictionary<long, Exception>> LoadBatchAsync(IReadOnlyList<long> keys, CancellationToken cancellationToken)
{
await using var dbContext = await _dbContext.CreateDbContextAsync(cancellationToken);
var result = await dbContext.Exceptions
.Where(s => keys.Contains(s.StockNumber))
.ToDictionaryAsync(t => t.StockNumber, cancellationToken);
return result;
}
}
Option-2: This problem remains same even if I hit dataLoader directly from query. Below is the query, dataloader.cs remains same as above.
Query.cs
public class ExceptionsQuery
{
public async Task<Exception> GetExceptionsAsync(
long stockNumber,
[Service(ServiceKind.Synchronized)] IExceptionService exceptionService,
ExceptionBatchDataLoader exceptionBatchDataLoader
)
{
var result = await exceptionBatchDataLoader.LoadAsync(
stockNumber,
CancellationToken.None
);
return result;
}
}
Exception
" in your business/domain model seeming as that's a very important class in .NET (and most other programming languages). Isn't there a better name you can use?