Linq-to-SQL ToDictionary ()


81

Як правильно перетворити два стовпці з SQL (2008) за допомогою Linq у словник (для кешування)?

На даний момент я переглядаю IQueryable b / c, я не можу змусити метод ToDictionary працювати. Будь-які ідеї? Це працює:

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

Що б я справді хотів зробити, це щось подібне, що, здається, не працює:

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

Але я отримую таку помилку: неможливо перетворити з 'System.Linq.IQueryable' на 'System.Collections.Generic.IEnumerable'

Відповіді:


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

На жаль, я, можливо, не був зрозумілим, я вже пробував це раніше, але це створює словник <рядок, # анонімний тип>, а не словник <рядок, рядок>
Codewerks

Спробуйте kvp => kvp.Value as string. Суть відповіді була .AsEnumerable().
yfeldblum

Дякую, так, я зрозумів, що потрібен AsEnumerable, але дзвінок ToDictionary все ще не працює. Обидва стовпці є вархарами в SQL, тому вони повертаються у вигляді рядків, але я не можу зрозуміти, як змусити його
заповнити

Я не знаю, чи це все ще актуально, але навіщо це AsEnumerableпотрібно? Для мене це працює і без цього, але, мабуть, Linq вже змінився (минуло 7 років)
Олександр Дерк

1
@AlexanderDerck - На той час це AsEnumerableбуло необхідно. Я точно не пам’ятаю, чому через весь цей час, але можливим поясненням є те, що ToDictionaryбув увімкнений метод розширення IEnumerable, але інтерфейсу для Linq-to-SQL не було IEnumerable.
yfeldblum

16

Ви лише визначаєте ключ, але потрібно також включити значення:

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

3
-1 Помилка полягає в тому, що <string, string>деталь змушує використовувати public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer);перевантаження замість public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);перевантаження.
user247702

Я думаю, що це ще потрібно .AsEnumerable()раніше.ToDictionary()
AceMark

працював ідеально ... нарешті той, кого я шукав,
Браян

9

Дякую, хлопці, ваші відповіді допомогли мені це виправити, мають бути:

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

5
Причина, по якій вам потрібен AsEnumerable (), полягає в тому, що LINQ to SQL не поєднує локальну та віддалену (SQL) обробку, тому це призводить до того, що перша частина виконується на сервері SQL, а потім остання частина виконується локально за допомогою LINQ to Objects, які можуть робити словники :)
DamienG

Має сенс. Крім того, другий параметр у ToDictionary потребує власних аргументів Func, що спонукало мене раніше.
Codewerks

1

Чому б ви створювали анонімний об’єкт для кожного елемента в таблиці лише для його перетворення?

Ви можете просто використати щось на зразок: IDictionary<string, string> dic = db.Table.ToDictionary(row => row.Key, row => row.Value); Можливо, вам доведеться включити виклик AsEnumerable () між таблицею та ToDictionary (). Я не знаю точного типу db.Table.


Також виправте перший зразок, ваша друга змінна циклу не відповідає декларації та використанню.


2
Тому що ToDictionaryє в пам'яті. Якщо не створювати анонімний об’єкт, усі стовпці отримуються з бази даних, а не лише ті, які вам потрібні.
user247702

ToDictionaryне знає про базову структуру, він просто викликає два зворотних виклики для ключа та значення (у цьому випадку просте властивість вибирає лямбди), тому цей ToDictionaryвиклик повинен бути функціонально еквівалентний foreach у прикладі, який він надав. Наскільки мені відомо, усі методи LINQ відкладені, тобто зворотні виклики викликаються лише тоді, коли це необхідно.
TWiStErRob

3
Якщо ви подивитесь на SQL Server Profiler, то побачите, що з анонімним об’єктом виділено лише два стовпці, і без нього виділено всі стовпці.
user247702
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.