2023-12-20

Adding UseProjection to Graphql Query Fails with Unexpected Execution Error in Linq Execution

I am new to Graphql and wanted to try it in an API written in c#.

I am using HotChocolate, EFCore 8, dotnet 8.

I have the following Classes

public class Batch
{
    public Batch()
    {
    }

    public Batch(string batchId, string tenantId, int paymentsCount, decimal totalAmount, string status,
        string statusDescription)
    {
        BatchId = batchId;
        TenantId = tenantId;
        PaymentsCount = paymentsCount;
        TotalAmount = totalAmount;
        Status = status;
        StatusDescription = statusDescription;
    }

    public string BatchId { get; set; }
    public string TenantId { get; set; }
    public int PaymentsCount { get; set; }
    public decimal TotalAmount { get; set; }
    public string Status { get; set; }
    public string StatusDescription { get; set; }
    [UseFiltering]
    [UseSorting]
    public ICollection<Payment> Payments { get; set; }
}

public class Payment
{
    public Payment()
    {
    }

    public string Id { get; set; }
    public string PayeeName { get; set; }
    public string CheckNumber { get; set; }
    //public List<string> InvoiceNumbers { get; set; }
    public DateTime PaymentDate { get; set; }
    public string Status { get; set; }
    public string StatusDescription { get; set; }
    public decimal Amount { get; set; }
}

This is the Grapql Query

public class BatchesQuery
{
    // Resolver
    [UsePaging(IncludeTotalCount = true)]
    [UseProjection]
    [UseFiltering]
    [UseSorting]
    public IQueryable<Batch> Batches([Service] PaymentDbContext paymentDbContext, string tenantId, IResolverContext context)
    {
        var paymentBatchesQueryable = paymentDbContext.PaymentBatches
            .Where(pb => pb.TenantId == tenantId)
            .OrderByDescending(pb => pb.CreatedTimestamp)
            .AsNoTracking();
        var paymentRequests = paymentBatchesQueryable.SelectMany(pb => pb.PaymentRequests);
        var payments = paymentRequests.Select(pr => new Payment()
        {
            Id = pr.PaymentRequestExternalId,
            PayeeName = pr.Payee.Name,
            CheckNumber = pr.Number,
            //InvoiceNumbers = pr.RemittanceDetails.Select(rd => rd.Number).ToList(),
            PaymentDate = pr.RequestDate,
            Status = pr.PaymentRequestStatusType.ToString(),
            StatusDescription = pr.PaymentRequestStatusType.ToString(),
            Amount = pr.RemittanceDetails.Sum(rd => rd.Net)
        });

        var paymentBatches = paymentBatchesQueryable
            .Select(pb => new Batch(pb.PaymentBatchExternalId,
                pb.TenantId,
                pb.PaymentRequests.Count,
                pb.PaymentRequests
                    .SelectMany(pr => pr.RemittanceDetails)
                    .Sum(rd => rd.Net),
                pb.PaymentBatchStatusType.ToString(),
                pb.PaymentBatchStatusType.ToString())
            {
                Payments = payments.ToList()
      
            });
       

        return paymentBatches;
    }
}

This is my Setup in Program.cs

builder.Services.AddGraphQLServer()
    .AddQueryType<BatchesQuery>()
    .AddProjections()
    .AddFiltering()
    .AddSorting()
    .RegisterDbContext<PaymentDbContext>();

I get the following error when I run this query:

query{
  batches(tenantId: "yKYrJLSUrE6XDWkrQC0e"){
    nodes{
      batchId
      payments{
        id
      }
    }
  }
}

Response:

{
  "errors": [
    {
      "message": "Unexpected Execution Error",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "batches"
      ],
      "extensions": {
        "message": "The LINQ expression 'p1 => new Payment{ Id = p1.Id }\r\n' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.",
        "stackTrace": "   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitLambda[T](Expression`1 lambdaExpression)\r\n   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression, Boolean applyDefaultTypeMapping)\r\n   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateProjection(Expression expression, Boolean applyDefaultTypeMapping)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment(MemberAssignment memberAssignment)\r\n   at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberInit(MemberInitExpression memberInitExpression)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)\r\n   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)\r\n   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)\r\n   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)\r\n   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)\r\n   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)\r\n   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)\r\n   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()\r\n   at HotChocolate.Types.Pagination.QueryableCursorPagination`1.ExecuteAsync(IQueryable`1 query, Int32 offset, CancellationToken cancellationToken)\r\n   at HotChocolate.Types.Pagination.CursorPaginationAlgorithm`2.ApplyPaginationAsync(TQuery query, CursorPagingArguments arguments, Nullable`1 totalCount, CancellationToken cancellationToken)\r\n   at HotChocolate.Types.Pagination.QueryableCursorPagingHandler`1.ResolveAsync(IResolverContext context, IQueryable`1 source, CursorPagingArguments arguments, CancellationToken cancellationToken)\r\n   at HotChocolate.Types.Pagination.CursorPagingHandler.HotChocolate.Types.Pagination.IPagingHandler.SliceAsync(IResolverContext context, Object source)\r\n   at HotChocolate.Types.Pagination.PagingMiddleware.InvokeAsync(IMiddlewareContext context)\r\n   at HotChocolate.Utilities.MiddlewareCompiler`1.ExpressionHelper.AwaitTaskHelper(Task task)\r\n   at HotChocolate.Execution.Processing.Tasks.ResolverTask.ExecuteResolverPipelineAsync(CancellationToken cancellationToken)\r\n   at HotChocolate.Execution.Processing.Tasks.ResolverTask.TryExecuteAsync(CancellationToken cancellationToken)"
      }
    }
  ],
  "data": {
    "batches": null
  }
}

I tried doing the recommendations provided in the response but none of them worked. This error goes away when I remove UseProjections annotation.

I am not sure what's happening. Could someone please explain ?



No comments:

Post a Comment