5

Trying to get a query with an anonymous type working:

let temporaryBookModel =
  query <@ context.Books 
    |> Seq.filter (fun book -> book.Id = bookId)
    |> Seq.map(fun item -> (item.Id, item.ParentUser.Id, item.ParentUser.Alias, item.Tagline, item.Title, item.Visible, item.CreatedDate))
    |> Seq.head @>

And I keep getting:

{"Only parameterless constructors and initializers are supported in LINQ to Entities."}

Which would make sense if I were mapping the values to a type directly, but anonymous types shouldn't throw this exception I would think since they are based on the object initializer functionality? Unfortunately anything I found on anonymous types seem to say this is the correct syntax. That or something like this:

let temporaryBookModel =
  query <@ context.Books 
    |> Seq.filter (fun book -> book.Id = bookId)
    |> Seq.map(fun item -> (("a", item.Id), ("b", item.ParentUser.Id), ("c", item.ParentUser.Alias), ("d", item.Tagline), ("e", item.Title, item.Visible), ("f", item.CreatedDate)))
    |> Seq.head @>
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Programmin Tool
  • 6,507
  • 11
  • 50
  • 68
  • F# has no concepts of 'anonymous types' -- that's a C# feature. Here you're constructing plain tuples. – ildjarn Dec 17 '11 at 21:35
  • Did you try isolating the error to a more specific construct (ie. first try Seq.map (fun i -> i.Id), the Seq.map (fun i -> i.Id, i.Id)), etc.? – fmr Dec 21 '11 at 00:57

2 Answers2

3

Does F# supports anonymous types?

As I know - it doesn't. But there are 2 possible ways for workarounds:

  • use tuples (as you're using)
  • use record types, but in this case you'll need to define record before. Something like this:
type Book =
    { 
        Id: int;
        ParentId: int;
        ParentAlias: string;
        TagLine: string;
        Title: string;
        Visible: bool;
        CreatedDate: DateTime;
    }

And usage code line will looks like:

...
|> Seq.map 
    (fun item -> 
        {
            Id = item.Id; 
            ParentId = item.ParentUser.Id;
            ParentAlias = item.ParentUser.Alias;
            TagLine = item.Tagline;
            Title = item.Title;
            Visible = item.Visible;
            CreatedDate = item.CreatedDate
        }) 

More explanations you can find in similar question here

Update:

Record types usage as for me is more elegant solution, BUT it looks like it doesn't not work with Entity Framework - F# -> Record with parameterless constructor?.

So according to Tomas Petricek answer - it has to be declared explicit type with parameters less constructor and necessary properties.

Community
  • 1
  • 1
Vitaliy
  • 2,744
  • 1
  • 24
  • 39
0

I don't have EF setup or your model but using the new F# 4.6 Anonymous Records feature this example which is very close to what you were attempting should work.

open System
open System.Linq

type Parent = {
    Id: int;
    Alias: string;
}

type Book = { 
    Id: int;
    ParentUser: Parent;
    Tagline: string;
    Title: string;
    Visible: bool;
    CreatedDate: DateTime }

[<EntryPoint>]
let main argv =

    let books = [| { Id = 1; ParentUser = { Id = 1; Alias = "ParentBook"; }; Tagline = "BattaBoom"; Title = "clear"; Visible = true; CreatedDate = DateTime.UtcNow }|]

    let bookId = 1

    let res = 
        books 
        |> Seq.filter (fun book -> book.Id = bookId)
        |> Seq.map(fun item -> {| Id = item.Id; ParentId = item.ParentUser.Id; ParentAlias = item.ParentUser.Alias; Tagline = item.Tagline; Title = item.Title; Visible = item.Visible; CreatedDate = item.CreatedDate |})
        |> Seq.head

    printfn "result %A" res

    0 // return an integer exit code

Notice the use of the | character on the insides of the curly braces of the anonymous record. This is what now distinguishes regular records from anonymous records in F#. Additionally in the example above notice that the property names in the Anonymous Record type need to be specified explicitly as unlike in C# the property names are not implicit based on their source property/field from the assignment. The feature to allow for implicit property names is suggested as a followup change in future language specifications.

jpierson
  • 16,435
  • 14
  • 105
  • 149