1

On my Hot Chocolate GraphQl queries with OffSetPagination and leveraging skip and take for my query.

I am noticing that skip and take filters works as expected on BE, but I am not seeing desired results either on playground or Postman. This is weird because when I hit breakpoint, it has valid data.

  • What am I doing wrong here?
  • Is this a bug in [UseOffsetPaging]?

References:

Code:

Query.cs

public class ExceptionsQuery
{
    [Authorize(policy: "SomePolicy")]
    [UseOffsetPaging]
    public async Task<List<ExceptionDto>> GetExceptionsAsync(
            ExceptionFiltersDto filters,
            [Service(ServiceKind.Synchronized)] IExceptionService exceptionService,
            CancellationToken cancellationToken,
            int skip = 0,
            int take = 0)
        // => await exceptionService.GetExceptions(filters, cancellationToken, skip, take);
    {
        var result = await exceptionService.GetExceptions(filters, cancellationToken, skip, take);
        return result; // This returns valid data
    }
}

service.cs

public async Task<List<ExceptionDto>> GetExceptions(ExceptionFiltersDto filters, CancellationToken cancellationToken, int skip = 0,int take = 0)
{
    try
    {
        
        if (string.IsNullOrWhiteSpace(filters.Location))
        {
            throw new ArgumentException("Location cannot be empty or whitespace.");
        }
        
        return await _projectXSupplyChainDbManagement.ExceptionRepository
            .GetExceptions(filters.Location, cancellationToken, filters.StockNumber, filters.InvoiceType, filters.SupplierName, skip, take)
            .Select(exceptionEntity => _mapper.Map<ExceptionDto>(exceptionEntity))
            .ToListAsync(cancellationToken: cancellationToken);
    }
    catch (Exception exception)
    {
        _logger.Error($"[{nameof(GetExceptions)}]: Error occurred - {{@exception}}", args: new object[] { exception.GetBaseException().Message});
        throw;
    }
}

Repo.cs

public IAsyncEnumerable<Exception> GetExceptions(string location,
    CancellationToken cancellationToken,
    string stockNumber = "",
    string invoiceFilter = "",
    string supplierName = "", int skip = 0,int take = 0)
{
    var query = _dbContext.Exception.AsNoTracking()
        .Where(_ => _.Location.Equals(location));

    if (!string.IsNullOrWhiteSpace(stockNumber))  query = query.Where(e => e.StockNumber.Equals(stockNumber));
    
    // return query
    //     .Skip(skip * take)
    //     .Take(take)
    //     .AsAsyncEnumerable();

    // return query
    //     .Skip(take * (skip - 1))
    //     .Take(take)
    //     .AsAsyncEnumerable();

    return query
        .Skip(skip)
        .Take(take)
        .AsAsyncEnumerable();
}

Screen Shots (Non-working example):

GraphQL.Server.Ui.Playground

enter image description here

Postman

enter image description here

// As you can see, here data is present but on above screenshots, you just see 2 records.

enter image description here

Working example:

enter image description here

enter image description here

enter image description here

GThree
  • 2,708
  • 7
  • 34
  • 67
  • In Query.cs, when you call `GetExceptions`, your first parameter supplied is your `filters` parameter which is an `ExceptionFiltersDto`, but the first parameter in the `GetExceptions` method signature is a `string` type. I'm not sure what's happening there. – Timothy G. Mar 29 '23 at 17:23
  • @TimothyG. Sorry for confusion. I was doing that in my `service.cs`, I have updated the question. I think something is going on with `[UseOffsetPaging]` which is causing this issue. – GThree Mar 29 '23 at 17:28

1 Answers1

1

So it turned out that I need to use CollectionSegment to achieve my desired result. If I make the following changes in my service.cs and query.cs, it is working.

Ref: https://chillicream.com/docs/hotchocolate/v13/fetching-data/pagination/#custom-pagination-logic-1

Updated Query.cs

public class ExceptionsQuery
{
    [Authorize(policy: "SomePolicy")]
    [UseOffsetPaging]
    public async Task<CollectionSegment<ExceptionDto>> GetExceptionsAsync(
            ExceptionFiltersDto filters,
            [Service(ServiceKind.Synchronized)] IExceptionService exceptionService,
            CancellationToken cancellationToken,
            int skip = 0,
            int take = 0)
        // => await exceptionService.GetExceptions(filters, cancellationToken, skip, take);
    {
        var result = await exceptionService.GetExceptions(filters, cancellationToken, skip, take);
        return result; // This returns valid data
    }
}

Updated Service.cs

public async Task<CollectionSegment<ExceptionDto>> GetExceptions(ExceptionFiltersDto filters, CancellationToken cancellationToken, int skip = 0,int take = 0)
{
    try
    {
        if (string.IsNullOrWhiteSpace(filters.Location))
        {
            throw new ArgumentException("Location cannot be empty or whitespace.");
        }
        
        var exceptions = await _projectXSupplyChainDbManagement.ExceptionRepository
            .GetExceptions(filters.Location, cancellationToken, filters.StockNumber, filters.InvoiceType,
                filters.SupplierName, skip, take)
            .Select(exceptionEntity => _mapper.Map<ExceptionDto>(exceptionEntity))
            .ToListAsync(cancellationToken: cancellationToken);

        var pageInfo = new CollectionSegmentInfo(false, false);

        var collectionSegment = new CollectionSegment<ExceptionDto>(
            exceptions.ToList().AsReadOnly(),
            pageInfo,
            ct => ValueTask.FromResult(exceptions.Count));

        return collectionSegment;

    }
    catch (Exception exception)
    {
        _logger.Error($"[{nameof(GetExceptions)}]: Error occurred - {{@exception}}", args: new object[] { exception.GetBaseException().Message});
        throw;
    }
}
GThree
  • 2,708
  • 7
  • 34
  • 67