Test fail - wonder what I am doing wrong? TypeMapping?
Test 'Microsoft.EntityFrameworkCore.Query.SimpleQuerySqlCeTest.Average_over_nested_subquery_is_client_eval(isAsync: True)' failed:
System.InvalidOperationException : An exception occurred while reading a database value. The expected type was 'System.Double' but the actual value was of type 'System.Decimal'.
---- System.InvalidCastException : Specified cast is not valid.
at Microsoft.EntityFrameworkCore.Storage.TypedRelationalValueBufferFactoryFactory.ThrowReadValueException[TValue](Exception exception, Object value, IPropertyBase property)
at lambda_method(Closure , DbDataReader )
at Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create(DbDataReader dataReader)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.<BufferlessMoveNext>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.<MoveNext>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.AsyncQueryMethodProvider.ParameterInjector`1.InjectParametersEnumerator.<MoveNext>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.AsyncSelectEnumerable`2.AsyncSelectEnumerator.<MoveNext>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Linq.AsyncEnumerable.<Average_>d__76.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor.<_ExecuteAsync>d__8`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.AsyncSelectEnumerable`2.AsyncSelectEnumerator.<MoveNext>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Linq.AsyncEnumerable.<Average_>d__80.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.TaskResultAsyncEnumerable`1.Enumerator.<MoveNext>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.<MoveNext>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<ExecuteSingletonAsyncQuery>d__21`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.TestUtilities.QueryAsserter`1.<AssertAverage>d__82`2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
----- Inner Stack Trace -----
at System.Data.SqlServerCe.SqlCeDataReader.GetDouble(Int32 ordinal)
at lambda_method(Closure , DbDataReader )
EF Core version: 2.2-preview3
Database Provider: SQL Compact
@maumar to take a look
Query plan for CE:
(QueryContext queryContext) => IEnumerable<decimal> _InterceptExceptions(
|__ source: IEnumerable<decimal> _ToSequence(() => decimal Average(IEnumerable<decimal> _ShapedQuery(
| |__ queryContext: queryContext,
| |__ shaperCommandContext: SelectExpression:
| | SELECT TOP(@__p_0) [c].[CustomerID]
| | FROM [Customers] AS [c]
| | ORDER BY [c].[CustomerID],
| |__ shaper: (QueryContext queryContext | ValueBuffer c) => (decimal)double Average(IEnumerable<double> _Select(
| |__ source: IEnumerable<ValueBuffer> _InjectParameters(
| | |__ queryContext: queryContext,
| | |__ source: IEnumerable<ValueBuffer> _ShapedQuery(
| | | |__ queryContext: queryContext,
| | | |__ shaperCommandContext: SelectExpression:
| | | | SELECT [o1].[OrderID], 5.0
| | | | FROM [Orders] AS [o1]
| | | | WHERE @_outer_CustomerID = [o1].[CustomerID],
| | | |__ shaper: ValueBufferShaper),
| | |__ parameterNames: new string[]{ "_outer_CustomerID" },
| | |__ parameterValues: new object[]{ string TryReadValue(c, 0, Customer.CustomerID) }),
| |__ selector: (ValueBuffer o) => (double)Nullable<double> TryReadValue(o, 1, null) + double GetResult(
| |__ valueBuffers: IEnumerable<ValueBuffer> _InjectParameters(
| | |__ queryContext: queryContext,
| | |__ source: IEnumerable<ValueBuffer> _Query(
| | | |__ queryContext: queryContext,
| | | |__ shaperCommandContext: SelectExpression:
| | | SELECT AVG(CAST([od7].[ProductID] AS float))
| | | FROM [Order Details] AS [od7]
| | | WHERE @_outer_OrderID2 = [od7].[OrderID]),
| | |__ parameterNames: new string[]{ "_outer_OrderID2" },
| | |__ parameterValues: new object[]{ (object)Nullable<int> TryReadValue(o, 0, Order.OrderID) }),
| |__ throwOnNullResult: True)))))),
|__ contextType: TestModels.Northwind.NorthwindRelationalContext,
|__ logger: DiagnosticsLogger<Query>,
|__ queryContext: Unhandled parameter: queryContext)
query plan for sql server:
(QueryContext queryContext) => IEnumerable<decimal> _InterceptExceptions(
|__ source: IEnumerable<decimal> _ToSequence(() => decimal Average(IEnumerable<decimal> _ShapedQuery(
| |__ queryContext: queryContext,
| |__ shaperCommandContext: SelectExpression:
| | SELECT TOP(@__p_0) [c].[CustomerID]
| | FROM [Customers] AS [c]
| | ORDER BY [c].[CustomerID],
| |__ shaper: (QueryContext queryContext | ValueBuffer c) => (decimal)double Average(IEnumerable<double> _Select(
| |__ source: IEnumerable<ValueBuffer> _InjectParameters(
| | |__ queryContext: queryContext,
| | |__ source: IEnumerable<ValueBuffer> _ShapedQuery(
| | | |__ queryContext: queryContext,
| | | |__ shaperCommandContext: SelectExpression:
| | | | SELECT [o1].[OrderID], 5.0E0
| | | | FROM [Orders] AS [o1]
| | | | WHERE @_outer_CustomerID = [o1].[CustomerID],
| | | |__ shaper: ValueBufferShaper),
| | |__ parameterNames: new string[]{ "_outer_CustomerID" },
| | |__ parameterValues: new object[]{ string TryReadValue(c, 0, Customer.CustomerID) }),
| |__ selector: (ValueBuffer o) => (double)Nullable<double> TryReadValue(o, 1, null) + double GetResult(
| |__ valueBuffers: IEnumerable<ValueBuffer> _InjectParameters(
| | |__ queryContext: queryContext,
| | |__ source: IEnumerable<ValueBuffer> _Query(
| | | |__ queryContext: queryContext,
| | | |__ shaperCommandContext: SelectExpression:
| | | SELECT AVG(CAST([od7].[ProductID] AS float))
| | | FROM [Order Details] AS [od7]
| | | WHERE @_outer_OrderID2 = [od7].[OrderID]),
| | |__ parameterNames: new string[]{ "_outer_OrderID2" },
| | |__ parameterValues: new object[]{ (object)Nullable<int> TryReadValue(o, 0, Order.OrderID) }),
| |__ throwOnNullResult: True)))))),
|__ contextType: TestModels.Northwind.NorthwindRelationalContext,
|__ logger: DiagnosticsLogger<Query>,
|__ queryContext: Unhandled parameter: queryContext)
The only difference is how constant 5 in the second query, so it does look like a type mapping issue. On sql server literal is printed in this for by SqlServerDoubleTypeMapping.GenerateNonNullSqlLiteral. SqlCE does seem to have a corresponding class - SqlCeFloatTypeMapping which is supposed to introduce a cast to float, but this doesn't happen.
The SQL CE provider was missing a DoubleTypeMapping! (The FloatTypemapping is for Single)
Most helpful comment
Query plan for CE:
query plan for sql server:
The only difference is how constant 5 in the second query, so it does look like a type mapping issue. On sql server literal is printed in this for by
SqlServerDoubleTypeMapping.GenerateNonNullSqlLiteral. SqlCE does seem to have a corresponding class -SqlCeFloatTypeMappingwhich is supposed to introduce a cast to float, but this doesn't happen.