Je travaille avec C # et .NET Framework 4.5.1 pour récupérer des données à partir d'une base de données SQL Server avec Entity Framework 6.1.3.
J'ai ceci:
codes = codesRepo.SearchFor(predicate)
.Select(c => new Tuple<string, byte>(c.Id, c.Flag))
.ToList();
Et quand je le lance, je reçois ce message:
Seuls les constructeurs et initialiseurs sans paramètre sont pris en charge dans LINQ to Entities.
Je ne sais pas comment je dois créer le Tuple car tous les exemples que j'ai trouvés sont pour la plupart comme celui-ci.
J'ai essayé ceci:
codes = codesRepo.SearchFor(predicate)
.Select(c => Tuple.Create(c.Id, c.Flag))
.ToList();
Et obtenez cette erreur:
LINQ to Entities ne reconnaît pas la méthode 'System.Tuple`2 [System.String, System.Byte] Create [String, Byte] (System.String, Byte)', et cette méthode ne peut pas être traduite en une expression de magasin.
Où est le problème?
c#
entity-framework
linq
tuples
VansFannel
la source
la source
Réponses:
Bien que la réponse d' octavioccl fonctionne, il est préférable de projeter d'abord le résultat de la requête en type anonyme, puis de passer à énumérable et de le convertir en tuple. De cette façon, votre requête ne récupérera de la base de données que les champs nécessaires.
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
Remarque: la règle ci-dessus s'applique à EF6. EF Core prend naturellement en charge les tuples (en projection ou en tant que clés de jointure / groupe) via le constructeur de tuple, par exemple la requête d'origine fonctionne simplement
codes = codesRepo.SearchFor(predicate) .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
mais pas la
Tuple.Create
méthode (EF Core 2.x).la source
.Select(c => new { c.Id, c.Flag, c.Foo?.Code })
ne marche pas.?.
n'est pas pris en charge dans les arborescences d'expression. Mais à part cela, vous pouvez étendre le type anonyme avec autant de valeurs que vous voulez - juste ne pas oublier de les nommer si nécessaire :) par exemplec => new { c.Id, c.Flag, Code = (int?)c.Foo.Code }
Juste une réponse mise à jour pour C # 7, vous pouvez maintenant utiliser une syntaxe plus simple pour créer des ValueTuples.
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => (c.Id, c.Flag)) .ToList();
Vous pouvez même nommer les propriétés du tuple maintenant:
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) // anonymous type .AsEnumerable() .Select(c => (Id: c.Id, Flag: c.Flag)) // ValueTuple .ToList();
Ainsi, au lieu de l'utiliser comme Item1 ou Item2, vous pouvez y accéder comme Id ou Flag.
Plus de documentation sur le choix entre anonyme et tuple
la source
Essaye ça:
Vous avez été informé que cela n'accepte pas dans LINQ les entités.
Une autre option serait de mettre le résultat en mémoire avant de le sélectionner. Si vous envisagez de faire cela, je vous recommanderais de faire tout le filtrage avant le .AsEnumerable () car cela signifie que vous ne récupérez que les résultats que vous voulez plutôt que de retirer toute la table, puis de filtrer.
ainsi Tuple.Create (c.Id, c.Flag) pourrait être changé en new Tuple (c.Id, c.Flag) si vous voulez rendre le code un peu plus explicite dans les types de tuples
la source
Dans linq aux entités, vous pouvez projeter sur un type anonyme ou sur un DTO.Pour éviter ce problème, vous pouvez utiliser la
AsEnumerable
méthode d'extension:codes = codesRepo.SearchFor(predicate).AsEnumerable(). .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
Cette méthode vous permet de travailler avec Linq to Object au lieu de Linq to Entities , donc après l'avoir appelée, vous pouvez projeter le résultat de votre requête dans tout ce dont vous avez besoin.L'avantage d'utiliser à la
AsEnumerable
placeToList
est queAsEnumerable
cela n'exécute pas la requête, cela préserve l'exécution différée. C'est une bonne idée de toujours filtrer vos données avant d'appeler l'une de ces méthodes.la source
J'ai trouvé la réponse:
la source
Utilisez cette méthode pour ce faire et utilisez le fichier async.
var codes = await codesRepo.SearchFor(predicate) .Select(s => new { Id = s.Id, Flag = s.Flag }).FirstOrDefaultAsync(); var return_Value = new Tuple<string, byte>(codes.Id, codes.Flag);
la source
Juste mes deux cents: cela m'a surpris à quelques reprises avec les noms de type:
Quelques exemples noddy:
private Tuple<string, byte> v1() { return new Tuple<string, byte>("", 1); } private (string, int) v2() { return ("", 1); } private (string Id, byte Flag) v3() { return ("", 1); }
Cordialement.
la source
public (string Id, byte Flag) SearchFor(Expression predicate)
, mais ce n'est pas la question. Deux cents ne devraient pas être une réponse, mais un commentaire.