When using .Count() following specific operations, the following exception is thrown :
System.InvalidCastException: Unable to cast object of type 'Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions.SqlFunctionExpression' to type 'System.Linq.Expressions.ConstantExpression'.
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalShapedQueryCompilingExpressionVisitor.RelationalProjectionBindingRemovingExpressionVisitor.GetProjectionIndex(ProjectionBindingExpression projectionBindingExpression)
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalShapedQueryCompilingExpressionVisitor.RelationalProjectionBindingRemovingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQueryExpression(ShapedQueryExpression shapedQueryExpression)
at Microsoft.EntityFrameworkCore.Query.Pipeline.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Pipeline.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
at Software.Controllers.ApplicationStatusController.Crash() in C:\software\src\Software\Controllers\ApplicationStatusController.cs:line 142
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
There are multiple ways to reproduce this error :
```c#
_context.Client
.Select(c => new
{
Id = c.Id.ToString("000000")
})
.Count();
```c#
_context.Client
.Select(c => c.Id.ToString("000000"))
.Count();
```c#
_context.Client
.Select(c => new
{
Id = c.Id.CodeFormat()
})
.Count();
`CodeFormat` being simply this :
```c#
public static class NamingTools
{
public static string CodeFormat(this int str)
{
return str.ToString();
}
}
Weirdly enough, doing .ToList() doesn't throw.
c#
_context.Client
.Select(c => new
{
Id = c.Id.ToString("000000")
})
.ToList(); // This works
EF Core version: 3.0.0-preview7.19365.7
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10 x64
IDE: Visual Studio 2019 16.2.0 Preview 4.0
@fschlaef All these are cases where the projection cannot (currently) be translated to SQL. In 3.0, we allow a final projection to be evaluated on the client, but then when the aggregate (Count) operator is applied the projection is no longer the final projection.
The plan for 3.0 is to throw an exception with a clearer message for this. (@smitpatel #16133 or is #15937 this case?)
For the future, putting this on the backlog to investigate silently dropping the projection when discarded by the final query anyway. However, we need to be careful about side-effects.
This has been fixed in my current work of Nav rewrite.
@smitpatel Merge before Monday?
:trollface: :trollface: :trollface: :trollface: :trollface: :trollface:
The mountain isn't going anywhere.... ๐
:trollface: :trollface: :trollface: :trollface: :trollface: :trollface:
๐จ โ ๐ฉ ๐ง keep on moving...
This has been fixed in my current work of Nav rewrite.
@smitpatel @ajcvickers
What does this statement refer to? Is it fixed or not? According to the issue milestone it is not?
I will put another +1 on this issue because this will be a big problem for everyone implementing a basic paginated list.
Example:
var entries =
(from c in context.Customers
select new CustomerListItem
{
c.Id,
c.Name,
ClientEvalProperty = // Some client eval expression
});
var viewModel = new ViewModel
{
Entries = entries.Skip(..).Take(..).ToList(),
Total = entries.Count() // Boom => Crash!
};
@davidroth - We believe that this issue has been fixed in latest daily builds.
@smitpatel Confirmed working with 3.0.0-rc1 ๐
@smitpatel Same here ๐ Works in 3.0.0-rc1.19424.9
Need to add a test for this.
This still fails: Unable to cast object of type 'Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlFunctionExpression' to type 'System.Linq.Expressions.ConstantExpression'.
Specifically with .Distinct() which obviously shouldn't be stopping any query from being executed properly. Or to put another way, if a query can execute fine and materialize as the last step without .Distinct, it certainly can with it since it's just SELECT DISTINCT ... instead of SELECT ...
Most helpful comment
This has been fixed in my current work of Nav rewrite.