The LINQ expression OrderBy DateTimeOffset.DateTime could not be translated

The LINQ expression OrderBy DateTimeOffset.DateTime could not be translated


0

I have a .NET Core project in which I have implemented this GraphQL query. The query works correctly, but the sorting by date is not working.

[UsePaging(MaxPageSize = 200, IncludeTotalCount = true)]
[UseProjection]
[UseFiltering]
[UseSorting]
public async Task<IQueryable<UserDto>> UserMetadatas(string myValue, [Service] ActivityEngineDataContext context,[Service] IMapper mapper)
{
  var entities = context.Users.Where(act => act.MyValue== myValue);
  return entities.ProjectTo<UserDto>(mapper.ConfigurationProvider);
}

Using AutoMapper, I have created the following projection to map the entity with the DTO.

CreateProjection<User, UserDto>()
  .ForMember(dest => dest.CreationDate, opt => opt.MapFrom(s => s.CreationDate.DateTime))
  .ForMember(dest => dest.LastUpdateDate, opt => opt.MapFrom(s => s.LastUpdateDate.DateTime));

I had to create this projection because the properties of the User class are DateTimeOffset type, whereas the properties of the UserDto class are DateTime type.

When I run this query from the Banana Cake Pop playground

query{
  activityInstancesMetadata(
    myValue: "value"
    where: {and: [{status: {eq: 32}}]}
    order: {lastUpdateDate: ASC}
    first: 20
  ) {
    nodes {
      creationDate
      lastUpdateDate
      id
      status
    }
    totalCount
  }
}

I have this error:

"The LINQ expression 'DbSet<User>()
.Where(a => a.MyValue== __myValue_0)
.OrderBy(a => a.LastUpdateDate.DateTime)' 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'

at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|15_0(ShapedQueryExpression translated, <>c__DisplayClass15_0& )
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
   at HotChocolate.Types.Pagination.QueryableCursorPagingHandler`1.ResolveAsync(IResolverContext context, IQueryable`1 source, CursorPagingArguments arguments, CancellationToken cancellationToken)
   at HotChocolate.Types.Pagination.CursorPagingHandler.HotChocolate.Types.Pagination.IPagingHandler.SliceAsync(IResolverContext context, Object source)
   at HotChocolate.Types.Pagination.PagingMiddleware.InvokeAsync(IMiddlewareContext context)
   at HotChocolate.Utilities.MiddlewareCompiler`1.ExpressionHelper.AwaitTaskHelper(Task task)
   at HotChocolate.Execution.Processing.Tasks.ResolverTask.ExecuteResolverPipelineAsync(CancellationToken cancellationToken)
   at HotChocolate.Execution.Processing.Tasks.ResolverTask.TryExecuteAsync(CancellationToken cancellationToken)"

Reading the stack trace and debugging, it seems that the issue is caused by Entity Framework, which, within the OrderBy method, inserts the expression set in the ForMember method of the Projection.

What I have tried so far

  • Set the conversion in the DataContext, in this way
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  foreach (var entityType in modelBuilder.Model.GetEntityTypes())
  {
    var properties = entityType.ClrType.GetProperties().Where(p => p.PropertyType == typeof(DateTimeOffset)
                                                                || p.PropertyType == typeof(DateTimeOffset?));
    foreach (var property in properties)
    {
      modelBuilder
          .Entity(entityType.Name)
          .Property(property.Name)
          .HasConversion(new DateTimeOffsetToStringConverter());
    }
  }
}
  • Double cast in the projection
CreateProjection<User, UserDto>()
  .ForMember(dest => dest.CreationDate, opt => opt.MapFrom(s => (DateTime)(object)s.CreationDate))
  .ForMember(dest => dest.LastUpdateDate, opt => opt.MapFrom(s => (DateTime)(object)s.LastUpdateDate));

This code works, but I encounter other issues when I invoke the query that returns a single record.

Is there a way to resolve this issue without using "ToList" in the query?


Load 6 more related questions


Show fewer related questions

0



Leave a Reply

Your email address will not be published. Required fields are marked *