web-dev-qa-db-fra.com

Créer un tuple dans une sélection Linq

Je travaille avec C # et .NET Framework 4.5.1 pour récupérer des données 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 les initialiseurs sans paramètre sont pris en charge dans LINQ aux entités.

Je ne sais pas comment je dois créer le tuple parce que tous les exemples que j'ai trouvés sont pour la plupart comme ceux-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] Créez la méthode [String, Byte] (System.String, Byte) 'et cette méthode ne peut pas être traduit dans une expression de magasin.

Où est le problème?

49
VansFannel

Alors que answer by octavioccl fonctionne, il est préférable de projeter d'abord le résultat de la requête en type anonyme, puis de basculer en énumérable et de le convertir en tuple. De cette façon, votre requête récupérera de la base de données uniquement 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();
68
Ivan Stoev

Essaye ça:

codes = codesRepo.SearchFor(predicate)
  .Select(c => Tuple.Create(c.Id, c.Flag))
  .ToList();

Être informé que cela n'accepte pas dans LINQ aux entités.

Une autre option consisterait à extraire le résultat en mémoire avant de le sélectionner. Si vous envisagez de le faire, je vous recommande de faire tout le filtrage avant .AsEnumerable (), car cela signifie que vous ne récupérez que les résultats souhaités, par opposition à la suppression de la totalité de la table, puis au filtrage.

codes = codesRepo.SearchFor(predicate).AsEnumerable()
  .Select(c => Tuple.Create(c.Id, c.Flag))
  .ToList();

de même, Tuple.Create (c.Id, c.Flag) pourrait être remplacé par un nouveau Tuple (c.Id, c.Flag) si vous voulez rendre le code un peu plus explicite dans les types de tuples. 

9
Dhunt

Dans linq to entités , vous pouvez projeter sur un type anonyme ou sur un DTO. Pour éviter ce problème, vous pouvez utiliser la méthode d’extension AsEnumerable:

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 à la place Linq to Entities , afin de l'appeler après, vous pouvez projeter le résultat de votre requête dans ce que vous souhaitez. L'avantage d'utiliser AsEnumerable à la place de ToList est que AsEnumerable est n'exécute pas la requête, il 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.

8
octavioccl

Juste une réponse mise à jour pour C # 7, vous pouvez maintenant utiliser une syntaxe plus simple pour créer 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 })
.AsEnumerable()
.Select(c => (Id: c.Id, Flag: c.Flag))
.ToList();

Ainsi, au lieu de l’utiliser comme Item1 ou Item2, vous pouvez y accéder en tant qu’Id ou Flag.

7
Rafael Merlin

J'ai trouvé la réponse:

codes = codesRepo.SearchFor(predicate)
      .ToList()
      .Select(c => Tuple.Create(c.Id, c.Flag))
      .ToList();
3
VansFannel

Utilisez cette méthode pour cela et utilisez le code asynchrone.

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);
1
MohammadSoori

Juste mes deux cents: cela m'a attrapé à quelques reprises avec les noms de type:

Quelques exemples de 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.

0
IbrarMumtaz