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:
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 query parsing
Pros and Cons
The advantages of making this adjustment to F# are:
Consistent between generated IQueryables
The disadvantages of making this adjustment to F# are: N/A
Extra information
Estimated cost (XS, S, M, L, XL, XXL): ?
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
For Readers
If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.
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:
Outputs:
The problem is:
The first case generates a plain constructor, and the second injects an IIFE for
Person.Namewhich causes inconsistency query parsingPros and Cons
The advantages of making this adjustment to F# are:
Consistent between generated IQueryables
The disadvantages of making this adjustment to F# are: N/A
Extra information
Estimated cost (XS, S, M, L, XL, XXL): ?
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
For Readers
If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.