I'm getting an ex褋eption when using this code
[<CLIMutable>]
type Product =
{
Id: string
Name: string
}
let db = new MyContext()
let q = query {
for p in db.Products do
select (p.Id, p.Name)
}
let result = q.ToListAsync().Result
If I choose select p or select p.Id insead of select (p.Id, p.Name) , this works fine. If I write ToList instead of ToListAsync this works fine as well. C# version with Tuples works well. With provided F# code it fails with this exception:
Unhandled Exception: System.InvalidOperationException: The source IQueryable doesn't implement IAsyncEnumerable<System.Tuple`2[System.String,System
.String]>. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.
at Microsoft.EntityFrameworkCore.Extensions.Internal.QueryableExtensions.AsAsyncEnumerable[TSource](IQueryable`1 source)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToke
n)
Also noticed that select { Id = p.Id; Name = p.Name } works, while select { Name = p.Name; Id = p.Id } doesn't and fails with exception:
Unhandled Exception: System.AggregateException: One or more errors occurred. (When called from 'VisitLambda', rewriting a node of type 'System.Linq
.Expressions.ParameterExpression' must return a non-null value of the same type. Alternatively, override 'VisitLambda' and change it to not visit c
hildren of this type.) ---> System.InvalidOperationException: When called from 'VisitLambda', rewriting a node of type 'System.Linq.Expressions.Par
ameterExpression' must return a non-null value of the same type. Alternatively, override 'VisitLambda' and change it to not visit children of this
type.
at System.Linq.Expressions.ExpressionVisitor.VisitAndConvert[T](ReadOnlyCollection`1 nodes, String callerName)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.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.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.Visit(Expression expression)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallE
xpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
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, INodeTypeProvider nodeTypeProvide
r, IDatabase database)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass24_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()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
This works:
let db = new MyContext()
let q1 = query {
for p in db.Products do
select p.Id
}
let result = q1.ToListAsync().Result
I.e. only the code with tuples (like select (p.Id, p.Name)) won't work.
q1 (from my sample) has Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[System.String] type (EF-friendly) while q (from @Lanayx sample) has System.Linq.EnumerableQuery`1[System.Tuple`2[System.String,System.String]] type (non EF-efiendly?).This also works:
let db = new MyContext()
let q1 = query {
for p in db.Products do
select (Tuple<string, string>(p.Id, p.Name))
}
let result = q1.ToListAsync().Result
There is another lingering bug in the treatment of tuples in query { ... } expressions e.g. #47, I assume this may be related
I assume using an intermediate record type will work.
There are two bugs here
1) The tuple doesn't work
2) The order of intermediate record fields matters, which shouldn't
@Lanayx could you please provide an example when the order matters? It'll be useful.
The example is already in the main post right above
Most helpful comment
The example is already in the main post right above