85 votes

Linq-à-SQL ToDictionary()

Comment convertir correctement deux colonnes de SQL (2008) en utilisant Linq dans un dictionnaire (pour la mise en cache) ?

Je boucle actuellement à travers le IQueryable parce que je n'arrive pas à faire fonctionner la méthode ToDictionary. Avez-vous des idées ? Cela fonctionne :

var query = from p in db.Table
            select p;

Dictionary<string, string> dic = new Dictionary<string, string>();

foreach (var p in query)
{
    dic.Add(sub.Key, sub.Value);
}

Ce que j'aimerais vraiment faire, c'est quelque chose comme ceci, qui ne semble pas fonctionner :

var dic = (from p in db.Table
             select new {p.Key, p.Value })
            .ToDictionary<string, string>(p => p.Key);

Mais je reçois cette erreur : Impossible de convertir 'System.Linq.IQueryable' en 'System.Collections.Generic.IEnumerable'.

128voto

yfeldblum Points 42613
var dictionary = db
    .Table
    .Select(p => new { p.Key, p.Value })
    .AsEnumerable()
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
;

0 votes

Désolé, je n'ai peut-être pas été clair, j'ai déjà essayé, mais cela crée un Dictionary<string, #Anonymous Type>, pas un Dictionary<string, string>.

0 votes

Essayez kvp => kvp.Value as string . Le point de la réponse était .AsEnumerable() .

0 votes

Merci, j'ai compris que AsEnumerable était nécessaire, mais l'appel à ToDictionary ne fonctionne toujours pas. Les deux colonnes sont des varchars en SQL, donc elles reviennent sous forme de chaînes de caractères, mais je n'arrive pas à trouver comment les faire entrer dans un Dic.....

17voto

CMS Points 315406

Vous ne définissez que la clé, mais vous devez également inclure la valeur :

var dic = (from p in db.Table
             select new {p.Key, p.Value })
            .ToDictionary(p => p.Key, p=> p.Value);

3 votes

-1 L'erreur est que le <string, string> lui fait utiliser le public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer); au lieu de la surcharge public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector); surcharge.

0 votes

Je pense qu'il faut encore .AsEnumerable() antes de .ToDictionary()

0 votes

A fonctionné parfaitement ... enfin celui que je recherchais

9voto

Codewerks Points 3284

Merci les gars, vos réponses m'ont aidé à réparer ça, ça devrait l'être :

var dic = db
        .Table
        .Select(p => new { p.Key, p.Value })
        .AsEnumerable()
        .ToDictionary(k=> k.Key, v => v.Value);

5 votes

La raison pour laquelle vous avez besoin de AsEnumerable() est que LINQ to SQL ne mélange pas le traitement local et distant (SQL). Ainsi, la première partie s'exécute sur le serveur SQL et la dernière partie ultérieure s'exécute localement en utilisant LINQ to Objects qui peut faire des dictionnaires :)

0 votes

C'est logique. De plus, le deuxième paramètre de ToDictionary a besoin de ses propres arguments Func, ce qui m'a fait trébucher plus tôt.

2voto

TWiStErRob Points 1233

Pourquoi créer un objet anonyme pour chaque élément du tableau juste pour le convertir ?

Vous pourriez simplement utiliser quelque chose comme : IDictionary<string, string> dic = db.Table.ToDictionary(row => row.Key, row => row.Value); Vous devrez peut-être inclure un appel AsEnumerable() entre Table et ToDictionary(). Je ne connais pas le type exact de db.Table.


Corrigez également le premier exemple, votre deuxième variable de boucle ne correspond pas à la déclaration et à l'utilisation.

2 votes

Parce que ToDictionary est en mémoire. Le fait de ne pas créer d'objet anonyme signifie que toutes les colonnes sont extraites de la base de données et pas seulement celles dont vous avez besoin.

0 votes

ToDictionary ne connaît pas la structure sous-jacente, il appelle juste les deux callbacks pour la clé et la valeur (dans ce cas, de simples lambdas de sélection de propriétés), donc ce ToDictionary devrait être fonctionnellement équivalent à l'appel foreach dans l'exemple qu'il a fourni. Pour autant que je sache, toutes les méthodes LINQ sont différées, ce qui signifie que les rappels ne sont appelés que si nécessaire.

3 votes

Si vous regardez avec SQL Server Profiler, vous verrez qu'avec un objet anonyme seules deux colonnes sont sélectionnées, et sans lui toutes les colonnes sont sélectionnées.

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