If just found Something Weird in a query.
I use .Net Core x64 SDK 2.1.500 on windows 10 x64
I'm trying to execute this request:
List<TicketListDto> dtos = await _ctx.Tickets.Include(i => i.Elements).AsNoTracking()
.Select(s => new TicketListDto
{
Id = s.Id,
Content = s.Elements.First().Content,
CreationDate = s.CreationDate,
LastModificationDate = s.Elements.LastOrDefault().StartDate,
Priority = (TicketPriority)s.Priority,
Title = s.Title,
Type = (TicketType)s.Type
})
.ToListAsync();
I got this error:
System.InvalidOperationException
HResult=0x80131509
Message=Rewriting child expression from type 'System.DateTime' to type 'System.Collections.Generic.IAsyncEnumerable`1[System.DateTime]' is not allowed, because it would change the meaning of the operation. If this is intentional, override 'VisitUnary' and change it to allow this rewrite.
Source=System.Linq.Expressions
StackTrace:
at System.Linq.Expressions.ExpressionVisitor.ValidateChildType(Type before, Type after, String methodName)
at System.Linq.Expressions.ExpressionVisitor.ValidateUnary(UnaryExpression before, UnaryExpression after)
at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.Visit(Expression expression)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.VisitMemberInit(MemberInitExpression memberInitExpression)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitSelectClause(SelectClause selectClause, QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitSelectClause(SelectClause selectClause, QueryModel queryModel)
at Remotion.Linq.Clauses.SelectClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor[TResult](QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileAsyncQuery[TResult](QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileAsyncQueryCore[TResult](Expression query, IQueryModelGenerator queryModelGenerator, IDatabase database)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass22_0`1.<CompileAsyncQuery>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddAsyncQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileAsyncQuery[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.System.Collections.Generic.IAsyncEnumerable<TResult>.GetEnumerator()
at System.Linq.AsyncEnumerable.<Aggregate_>d__6`3.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at ProjectManagement.Services.TicketService.<GetTicketListDtoAsync>d__2.MoveNext() in C:\Team Foundation\ProjectManagement\ProjectManagement.Services\TicketService.cs:line 29
but if I replace
LastModificationDate = s.Elements.LastOrDefault().StartDate,
or
LastModificationDate = s.Elements.Last().StartDate,
with
LastModificationDate = s.Elements.FirstOrDefault().StartDate,
or
LastModificationDate = s.Elements.First().StartDate,
It works fine.
Is someone have an idea ?
Thanks
@JulienM28, just tip. If you need last element, you have to know how they should be ordered. I assume that EF guys can transform your query to
LastModificationDate = s.Elements.OrderByDescending(e => e.SomeId).FirstOrDefault().StartDate,
It鈥檚 because of RDBMS nature. But ensure that this what you need. Without ordering FirstOrDefault or LastOrDefault requests have undefined behavior.
The main cause of error was client eval of LastOrDefault which happened because of lack of ordering.
In 3.0, we throw exception for above case as translation failure. If an order by is added before LastOrDefault then we translate it to server successfully.
Added test to cover later scenario in #17932
Most helpful comment
@JulienM28, just tip. If you need last element, you have to know how they should be ordered. I assume that EF guys can transform your query to
It鈥檚 because of RDBMS nature. But ensure that this what you need. Without ordering
FirstOrDefaultorLastOrDefaultrequests have undefined behavior.