5 votes

Entity Framework et types anonymes en F#

J'essaie de faire fonctionner une requête avec un type anonyme :

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 @>

Et je continue à recevoir :

{"Seuls les constructeurs sans paramètre et les initialisateurs sont supportés dans LINQ to Entities."}

Ce qui serait logique si je faisais correspondre les valeurs à un type directement, mais les types anonymes ne devraient pas lever cette exception puisqu'ils sont basés sur la fonctionnalité de l'initialisateur d'objet ? Malheureusement, tout ce que j'ai trouvé sur les types anonymes semble dire que c'est la syntaxe correcte. Cela ou quelque chose comme ceci :

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 @>

3voto

Vitaliy Points 1466

F# supporte-t-il les types anonymes ?

Comme je le sais, ce n'est pas le cas. Mais il y a deux façons possibles de contourner le problème :

  • utiliser des tuples (comme vous le faites)
  • utilisent des types d'enregistrement, mais dans ce cas, vous devrez définir l'enregistrement avant. Quelque chose comme ceci :

    type Book = { Id: int; ParentId: int; ParentAlias: string; TagLine: string; Title: string; Visible: bool; CreatedDate: DateTime; }

Et la ligne de code d'utilisation ressemblera à ceci :

...
|> 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
        }) 

Vous trouverez plus d'explications dans une question similaire ici

Mise à jour :

L'utilisation des types d'enregistrement est pour moi une solution plus élégante, MAIS il semble qu'il ne fonctionne pas avec Entity Framework -. F# -> Enregistrement avec constructeur sans paramètre ? .

Donc, selon la réponse de Tomas Petricek - il doit être déclaré comme un type explicite avec des paramètres, moins le constructeur et les propriétés nécessaires.

0voto

jpierson Points 3871

Je n'ai pas la configuration EF ou votre modèle mais en utilisant le nouveau F# 4.6 Enregistrements anonymes Cet exemple, qui est très proche de ce que vous essayez de faire, devrait fonctionner.

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

Remarquez l'utilisation de la | à l'intérieur des accolades de l'enregistrement anonyme. C'est ce qui distingue maintenant les enregistrements réguliers des enregistrements anonymes dans F#. En outre, dans l'exemple ci-dessus, vous remarquerez que les noms de propriété dans le type d'enregistrement anonyme doivent être spécifiés explicitement car, contrairement à ce qui se passe en C#, les noms de propriété ne sont pas implicites en fonction de leur propriété/champ source dans l'affectation. La fonctionnalité permettant de noms de propriétés implicites est suggéré comme un changement de suivi dans les futures spécifications du langage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X