Zrádná metoda ToDictionary a rozhraní IQueryable

Miroslav Holec

Miroslav Holec

Publikován 24. listopadu 2015 , aktualizace: 29. března 2016 | Devtips

Tento článek je starší 18 měsíců a je proto možné, že popisuje postupy nebo technologie, které v uplynulé době mohly doznat výraznějších změn. Názory a myšlenky v tomto článku již nemusí vyjadřovat současné stanovisko autora nebo autorů. Článek byl napsán 24. listopadu 2015.

Pokud s pomocí Entity Framework často selectujete data z databáze do dictionaries, pravděpodobně pro tento účel používáte extension metodu ToDictionary. Je to ale s ohledem na výkonnost správné? O tom, že se bude jednat o výkonnostní risk se můžeme přesvědčit už z kódu této extension metody. Všimněte si, že metoda pracuje s IEnumerable.

.NET Core

Nová podzimní školení .NET Core a Entity Framework Core

Chcete se dozvědět o novinkách v moderním vývojářském stacku (ASP).NET Core a Entity Framework Core? Připravil jsem krátká úderná školení, ve kterých se zaměřím na nové aspekty těchto technologií. Žádná omáčka a žádné opáčko toho, co už znáte. Prostě jen to nové.

[__DynamicallyInvokable]
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
{
  return Enumerable.ToDictionary<TSource, TKey, TElement>(source, keySelector, elementSelector, (IEqualityComparer<TKey>) null);
}

Začněme tedy tím, že:

using (var db = new BookStoreContext())
{
	Dictionary<int, string> books = context.Books.ToDictionary(x => x.BookId, x => x.Title);
}

je výkonnostně naprosto špatně. Výsledný dotaz totiž vypadá například takto:

SELECT [Extent1].[BookId]        AS [BookId],
       [Extent1].[CategoryId]    AS [CategoryId],
       [Extent1].[Title]         AS [Title],
       [Extent1].[Added]         AS [Added],
       [Extent1].[Url]           AS [Url]
FROM   [dbo].[Books] AS [Extent1]

Klasický SELECT * FROM pak s rostoucím množstvím atributů a případných joinů způsobí dotázání a přenos enormního množství dat. Jednoduché řešení je provést před voláním extension metody projekci:

context.Books.Select(x => new {x.BookId, x.Title}).ToDictionary(x => x.BookId, x => x.Title)

Tím už dostaneme chtěný dotaz:

SELECT [Extent1].[BookId]        AS [BookId],
       [Extent1].[Title]         AS [Title]
FROM   [dbo].[Books] AS [Extent1]

Pokud data načítáme do dictionaries, s největší pravděpodobností se bude jednat o read-only kolekce. Z výkonnostnho hlediska pak nic nebrání provést poslední krok optimalizace:

context.Books.AsNoTracking().Select(x => new {x.BookId, x.Title}).ToDictionary(x => x.BookId, x => x.Title)

Extension metoda AsNoTracking() vypne trackování změn pro aktuální DbQuery a výrazně ušetří kontextu od správy dat. Dodávám, že výkonnostní rozdíl mezi prvním a posledním příkladem se na časech projevuje i ve dvou řádech.

Zeptejte se


Školení webového vývoje

Krátká a úderná školení zaměřená na skutečné novinky ve světě webového vývoje.

DatumNázev školeníMístoDélkaCenaStav
08.10.2018Infrastruktura ASP.NET CorePraha3 h.1 500 KčVolná místana registraci ⇒
08.10.2018Úvod do Entity Framework CorePraha4 h.1 900 KčVolná místana registraci ⇒
09.10.2018RESTful Web API s ASP.NET Core MVCPraha3 h.1 500 KčVolná místana registraci ⇒
09.10.2018Diagnostika aplikací s App insightsPraha4 h.1 900 KčVolná místana registraci ⇒

HOLEC, Miroslav. Zrádná metoda ToDictionary a rozhraní IQueryable. Azure & ASP.NET Core Blog [online]. Praha: Miroslav Holec, ©2010-2015. Poslední změna článku 29.3.2016 [vid. 2018-09-19]. Dostupné z: https://www.miroslavholec.cz/blog/zradna-metoda-todictionary-a-rozhrani-iqueryable