Linq-to-SQL ToDictionary ()

80

Wie konvertiere ich zwei Spalten aus SQL (2008) mit Linq ordnungsgemäß in ein Wörterbuch (zum Zwischenspeichern)?

Ich durchlaufe derzeit das IQueryable b / c. Ich kann die ToDictionary-Methode nicht zum Laufen bringen. Irgendwelche Ideen? Das funktioniert:

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

Was ich wirklich gerne machen würde, ist so etwas, was nicht zu funktionieren scheint:

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

Ich erhalte jedoch die folgende Fehlermeldung: Konvertierung von 'System.Linq.IQueryable' in 'System.Collections.Generic.IEnumerable' nicht möglich.

Codewerks
quelle

Antworten:

120
var dictionary = db
    .Table
    .Select(p => new { p.Key, p.Value })
    .AsEnumerable()
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
;
Yfeldblum
quelle
Entschuldigung, ich war vielleicht nicht klar, ich habe es schon einmal versucht, aber dies erstellt ein Wörterbuch <string, #Anonymous Type>, nicht Dictionary <string, string>
Codewerks
Versuchen Sie es kvp => kvp.Value as string. Der Punkt der Antwort war .AsEnumerable().
Yfeldblum
Danke, ja, ich dachte, AsEnumerable wird benötigt, aber der ToDictionary-Aufruf funktioniert immer noch nicht. Beide Spalten sind Varchars in SQL, daher kommen sie als Zeichenfolgen zurück, aber ich kann nicht herausfinden, wie ich sie in ein Dic
einfügen kann
Ich weiß nicht, ob dies noch relevant ist, aber warum wird das AsEnumerablebenötigt? Für mich funktioniert es auch ohne das, aber wahrscheinlich hat sich Linq bereits geändert (7 Jahre sind vergangen)
Alexander Derck
1
@AlexanderDerck - Zu der Zeit war das AsEnumerablenotwendig. Ich erinnere mich nicht genau, warum nach all dieser Zeit, aber eine mögliche Erklärung ist, dass ToDictionaryes sich um eine Erweiterungsmethode handelte IEnumerable, die Schnittstelle für Linq-to-SQL jedoch nicht IEnumerable.
Yfeldblum
16

Sie definieren nur den Schlüssel, müssen aber auch den Wert angeben:

var dic = (from p in db.Table
             select new {p.Key, p.Value })
            .ToDictionary(p => p.Key, p=> p.Value);
Christian C. Salvadó
quelle
3
-1 Der Fehler besteht darin, dass das <string, string>Teil die public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer);Überlastung anstelle der public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);Überlastung verwendet.
user247702
Ich denke, es braucht noch .AsEnumerable()vorher.ToDictionary()
AceMark
hat perfekt funktioniert ... endlich das, wonach ich gesucht habe
Brian
9

Danke Jungs, eure Antworten haben mir geholfen, das zu beheben, sollten sein:

var dic = db
        .Table
        .Select(p => new { p.Key, p.Value })
        .AsEnumerable()
        .ToDictionary(k=> k.Key, v => v.Value);
Codewerks
quelle
5
Der Grund, warum Sie AsEnumerable () benötigen, ist, dass LINQ to SQL keine lokale und Remote-Verarbeitung (SQL) mischt. Dies führt dazu, dass der erste Teil auf dem SQL Server ausgeführt wird und der letzte nachfolgende Teil lokal mit LINQ to Objects ausgeführt wird Wörterbücher machen :)
DamienG
Macht Sinn. Außerdem benötigt der zweite Parameter in ToDictionary seine eigenen Func-Argumente, die mich früher ausgelöst haben.
Codewerks
1

Warum sollten Sie für jedes Element in der Tabelle ein anonymes Objekt erstellen, um es zu konvertieren?

Sie können einfach IDictionary<string, string> dic = db.Table.ToDictionary(row => row.Key, row => row.Value); Folgendes verwenden: Möglicherweise müssen Sie einen AsEnumerable () -Aufruf zwischen Table und ToDictionary () einfügen. Ich kenne den genauen Typ der Datenbank nicht.


Korrigieren Sie auch das erste Beispiel. Ihre zweite Schleifenvariable stimmt bei Deklaration und Verwendung nicht überein.

TWiStErRob
quelle
2
Weil ToDictionaryim Speicher ist. Wenn Sie kein anonymes Objekt erstellen, werden alle Spalten aus der Datenbank abgerufen und nicht nur die von Ihnen benötigten.
user247702
ToDictionarykennt die zugrunde liegende Struktur nicht, ruft nur die beiden Rückrufe für Schlüssel und Wert auf (in diesem Fall einfache Eigenschaft zur Auswahl von Lambdas), daher sollte dieser ToDictionaryAufruf funktional dem foreach in dem von ihm bereitgestellten Beispiel entsprechen. Soweit ich weiß, werden alle LINQ-Methoden zurückgestellt, dh Rückrufe werden nur bei Bedarf aufgerufen.
TWiStErRob
3
Wenn Sie mit SQL Server Profiler suchen, werden Sie feststellen, dass bei einem anonymen Objekt nur zwei Spalten ausgewählt sind und ohne dieses alle Spalten ausgewählt sind.
user247702