Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent anonymous record instantiation on IQueryable #15648

Open
lucasteles opened this issue Jul 20, 2023 · 2 comments
Open

Inconsistent anonymous record instantiation on IQueryable #15648

lucasteles opened this issue Jul 20, 2023 · 2 comments
Labels
Area-Queries Query expressions and library implementation Bug Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code.
Milestone

Comments

@lucasteles
Copy link

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)
@0101
Copy link
Contributor

0101 commented Jul 24, 2023

The behavior seems to depend on whether the fields are in alphabetical order or not.

...
.Select(fun x -> {| Other = {| B = x.Person.Name; A = x.Person.Id |} |}) // => Invoke
...
.Select(fun x -> {| Other = {| A = x.Person.Name; B = x.Person.Id |} |}) // => No Invoke
...
      ```

@0101 0101 added Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code. Area-Queries Query expressions and library implementation and removed Needs-Triage labels Jul 24, 2023
@edgarfgp
Copy link
Contributor

edgarfgp commented Jul 30, 2023

Duplicate of #11131 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Queries Query expressions and library implementation Bug Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code.
Projects
None yet
Development

No branches or pull requests

3 participants