When projecting an anonymous record on IQueryable the generated tree contains a Delegate.Invoke for the anonymous type constructor, this causes some parsers/drivers to be unable to understand the operation (eg. Entity Framework)
This looks to happen when accessing deep members and having long record member names.
Repro steps
Provide the steps required to reproduce the problem:
open System
open System.Linq
type Person = { Name: string; Id : int }
type Wrapper = { Person: Person }
let data = [
{ Person = { Name = "One"; Id = 1 } }
{ Person = { Name = "Two"; Id = 2 } }
{ Person = { Name = "Three"; Id = 3 } }
]
let queryWithInvoke =
data
.AsQueryable()
.Select(fun x -> {| Other = {| Name = x.Person.Name; Id = x.Person.Id |} |})
// short label names do not generate an invoke call
let queryWithoutInvoke =
data
.AsQueryable()
.Select(fun x -> {| Other = {| A = x.Person.Name; B = x.Person.Id |} |})
printfn "%A" queryWithInvoke.Expression;
printfn "------"
printfn "%A" queryWithoutInvoke.Expression
Outputs:
[{ Person = { Name = "One"
Id = 9a093c1d-9a3c-4366-806e-7c32b4388a1d }
Value = 0 }; { Person = { Name = "Two"
Id = ded2fd37-69cd-4d56-bc05-69e539264301 }
Value = 1 }; { Person = { Name = "Three"
Id = 798c98fb-a772-4911-84cc-63101b369cb9 }
Value = 2 }].Select(x => new <>f__AnonymousType1021199106`1(Name => new <>f__AnonymousType3987781292`2(x.Person.Id, Name).Invoke(x.Person.Name)))
------
[{ Person = { Name = "One"
Id = 9a093c1d-9a3c-4366-806e-7c32b4388a1d }
Value = 0 }; { Person = { Name = "Two"
Id = ded2fd37-69cd-4d56-bc05-69e539264301 }
Value = 1 }; { Person = { Name = "Three"
Id = 798c98fb-a772-4911-84cc-63101b369cb9 }
Value = 2 }].Select(x => new <>f__AnonymousType1021199106`1(new <>f__AnonymousType2589797714`2(x.Person.Name, x.Person.Id)))
The problem is:
new <>f__AnonymousType1021199106`1(
Name => new <>f__AnonymousType3987781292`2(
x.Person.Id, Name
)
.Invoke(x.Person.Name)) // <- here
The first case generates a plain constructor, and the second injects an IIFE for Person.Name which causes inconsistency in query parsing
from: fsharp/fslang-suggestions#1249
Expected behavior
No difference between the expressions
Actual behavior
Delegate invocation inside the expression
Known workarounds
Use small record labels
Related information
- Windows 11 / MacOs / Arch Linux
- .NET6
- Editing Tools (any)
When projecting an anonymous record on
IQueryablethe generated tree contains aDelegate.Invokefor the anonymous type constructor, this causes some parsers/drivers to be unable to understand the operation (eg.Entity Framework)This looks to happen when accessing deep members and having long record member names.
Repro steps
Provide the steps required to reproduce the problem:
Outputs:
The problem is:
The first case generates a plain constructor, and the second injects an IIFE for
Person.Namewhich causes inconsistency in query parsingfrom: fsharp/fslang-suggestions#1249
Expected behavior
No difference between the expressions
Actual behavior
Delegate invocation inside the expression
Known workarounds
Use small record labels
Related information