8. díl - LINQ provideři, anonymní typy, řazení a seskupování

C# .NET Kolekce a LINQ LINQ provideři, anonymní typy, řazení a seskupování

V minulém dílu našeho seriálu tutoriálů o C# jsme si uvedli technologii LINQ a vytvořili svůj první jednoduchý dotaz. Dnes budeme s LINQem pokračovat.

Provideři

Zmínili jsme si, že LINQ funguje díky tzv. providerům. To jsou implementace metod pro různé platformy, aby na nich bylo možné volat LINQ dotazy. Vyjmenujme si základní providery pro LINQ a ke každému si něco málo řekněme.

Provideři v .NETu:

Nekteré providery dodává Microsoft přímo v .NETu, jsou to následující:

  • LINQ to Objects - Provider umožňuje klást dotazy nad základními kolekcemi. Používali jsme ho minule pro dotazy nad polem, stejně tak se můžeme dotazovat nad Listy a dalšími kolekcemi z .NETu. LINQ to Objects tedy pracuje s daty v operační paměti.
  • LINQ to SQL - Provider mapuje LINQ příkazy na SQL dotazy a umožňuje nám pracovat s MS-SQL databází. Funguje to jak pro klasický MS SQL Server, tak pro verzi MS-SQL Express a dokonce i s malým hackem pro verzi MS-SQL CE (Compact Edition, kde je databáze uložena v jediném souboru a není třeba nainstalovaný server). Provider nám poskytuje tzv. ORM (viz další díly seriálu). Práce s databází je plně objektová, v seriálu s tímto providerem budeme často pracovat.
  • LINQ to XML - Provider umožňuje dotazy nad XML souborem. Stejně jako u LINQ to SQL se jedná o objektový přístup.

Provideři třetích stran

Jelikož je samozřejmě možné napsat si provider vlastní, mnoho hotových řešení existuje i od třetích stran.

  • DbLinq - Nejpoužívanější provider třetí strany, který umožňuje používat technologii LINQ na databázích MySQL, SQLite, Oracle, Postgre SQL, Firebird a dalších velmi používaných databázových platformách.
  • LINQ to Excel - Provider umožňuje pracovat s Excelovou tabulkou (Excelovým dokumentem) jako s databází.
  • LINQ to JSON - Provider pro dotazování nad soubory formátu JSON.
  • LINQ to Amazon - LINQ to Amazon se často uvádí jako ukázka provideru třetí strany. Pomocí LINQ dotazů můžeme vyhledávat v knihách, které tento internetový obchod nabízí.

Vidíme, že providerů je dostatek a jakmile umíme LINQ používat, není problém ho použít téměř na vše. V seriálu se brzy zaměříme hlavně na LINQ to SQL.

Pozn.: Kromě těchto providerů existuje ještě Entity Framework, někdy chybně zaměňovaný za LINQ to Entities, který je jedna jeho součást. Jedná se o technologii komplexnejší než LINQ to SQL s kvalitnějším mapováním, jejíž vývoj také trval déle a dostala se do .NET frameworku později. Kvůli poměrně vysoké složitosti to ale nevypadá, že LINQ to SQL nahradí.

Anonymní typy

Abychom mohli vytvářet složitější dotazy, přesněji dostat z dotazu jen tu část dat, která nás zajímá, budeme používat tzv. anonymní typy. Anonymní typ se chová jako instance třídy, ale žádnou třídu k tomuto účelu deklarovat nemusíme. Zkusme si to:

var anonym = new { Jmeno="Anonym", Prijmeni="Anonymní", Vek="18" };
Console.WriteLine(anonym.Jmeno);
Console.WriteLine(anonym.Prijmeni);
Console.WriteLine(anonym.Vek);

Výstup takového programu bude následující:

Anonymní typy v C# .NET

Vytvořili jsme si anonymní datový typ, který má v sobě 3 atributy. Do nich jsme rovnou uložili hodnoty a celou strukturu vložili do proměnné typu var. Výsledný datový typ je velmi podivný a bez klíčového slova var bychom takovou proměnnou těžko vytvořili.

K čemu je výhoda takových typů? V dotazech si můžeme v selectu namapovat úplně co chceme. Mějme kolekci s auty a řidiči. Budeme chtít vybrat vždy SPZ auta a celé jméno jeho řidiče u červených aut. Řidič má na sobě vlastnosti Jmeno a Prijmeni, auto má na sobě vlastnosti Barva, Ridic a Spz. Dotaz by vypadal takto:

var dotaz = from a in auta
            where (a.Barva = "cervena")
            select new { a.Spz, JmenoRidice = a.Ridic.Jmeno + " " + a.Ridic.Prijmeni };

Aby nám dotaz mohl vrátit takto složitý výsledek, musí si na něj vytvořit právě anonymní datový typ. Výsledek dotazu bude tedy kolekce prvků, kde každý prvek bude mít vlastnosti Spz a JmenoRidice. Všimněte si, že jsme jednou napsali jen a.SPz a podruhé JmenoRidice = .... Pokud chceme vložit již nějakou existující vlastnost se stejným názvem, stačí uvést pouze tu. Pokud chceme název jiný, musíme použít NazevVlastnosti = hodnota.

Pozor: Anonymními typy bychom měli šetřit stejně jako např. s klíčovým slovem var. Opět se jedná o funkcionalitu vytvořenou pro určitý účel, zejména do LINQ dotazů. Nepoužívejte anonymní typy v běžném programování namísto tříd, snižujete tak kvalitu zdrojového kódu i výsledné aplikace. Atributy anonymních typů jsou jen pro čtení, přesněji se jedná o vlastnosti. Většinou se chceme anonymním typům vyhnout a raději navrhneme datavou vrstvu aplikace tak, aby nám výhovovala a nemuseli jsme psát příliš složité dotazy. Použitím anonymních typů se zbavujeme relací mezi jednotlivými entitami, což může vést ve složitější aplikaci k mnoha problémům. Lépe bychom konkrétní situaci mohli řešit tak, že autu vytvoříme vlastnost JmenoRidice a v selectu vybereme celé auto, tedy jednoduše select a. Jméno řidiče si poté vytahneme stejně jednoduše, jako s anonymním typem. Zároveň pracujeme s celým autem včetně všech vazeb a ne s nějakou neidentifikova­telnou anonymní entitou. Stejně tak ale mají anonymní typy své místo pro složitější, zejména jednoúčelové dotazy a budou se často objevovat v ukázkových dotazech v těchto tutoriálech.

Již umíme vše potřebné k tomu, abychom si ukázali syntaxi pokročilejších dotazů.

Řazení a seskupování

Minule jsme si uvedli klíčová slova from, where a select. Ukažme si ještě 2 základní operátory, než se pustíme do podrobného popisu syntaxe LINQu.

orderby

Pokud chceme výsledky dotazu seřadit, použijeme operátor orderby:

var dotaz = from u in uzivatele
            where (u.Vek > 15)
            orderby u.Jmeno
            select u.Vek;

Jak již víme, C# si tento dotaz vnitřně přeloží na metody:

var dotaz = uzivatele.Where(u => u.Vek > 15).OrderBy(u => u.Jmeno).Select(u => u.Vek);

Všechny příkazy z LINQ mají své metody, to bylo jen pro upomenutí, dále je již nebudu uvádět.

Výchozí směr řazení je od nejmenších hodnot po největší (zde konkrétně řadíme podle jména uživatele, tedy od A do Z). Pokud chceme řadit opačně, uvedeme klíčové slovo descending:

var dotaz = from u in uzivatele
            where (u.Vek > 15)
            orderby u.Jmeno descending
            select u.Vek;

V prvním případě jsme mohli použít ascending, ale není to nutné. Pokud jde o metody, použije se OrderByDescen­ding().

Řadit můžeme i podle více kritérií, jednoduše je oddělíme čárkou, ta první mají přednost:

var dotaz = from u in uzivatele
            where (u.Vek > 15)
            orderby u.Jmeno, u.Prijmeni
            select u.Vek;

Tento dotaz si C# přeloží na:

var dotaz = uzivatele.Where(u => u.Vek > 15).OrderBy(u => u.Jmeno).ThenBy(u => u.Prijmeni).Se­lect(u => u.Vek);

group (seskupování)

V dotazech často využíváme seskupování (grouping). Můžeme tak jednoduše prvky seskupit podle určitých kritérii. Ukažme si příkad jak bychom seskupili uživatele do skupin podle jejich věku:

var dotaz = from u in uzivatele
            group u by u.Vek into vekovaSkupina
            select new { Vek = vekovaSkupina.Key, Uzivatele = vekovaSkupina };

Co že jsme to provedli? Seskupili jsme uživatele podle jejich věku do vekovaSkupina, což je kolekce, která obsahuje vždy uživatele se stejným věkem. Je tam tedy např, skupina 15, skupina 16, 17 atd. Dále vybíráme jak bude skupina vypadat. Bude obsahovat věk, ten vezmeme z klíče skupiny, kterým je právě věk, jelikož podle něj seskupujeme. Druhou vlastností skupiny bude kolekce uživatelů, tam uložíme tu aktuální skupinu uživatelů pro daný věk.

Přejděme k výpisu:

foreach (var skupina in dotaz)
{
        Console.WriteLine(skupina.Vek);
        foreach (var uzivatel in skupina.Uzivatele)
                Console.WriteLine(uzivatel.Jmeno);
}

Nejprve proiterujeme všechny skupiny a pro každou skupiny vypíšeme její věk a poté uživatele v ní obsažené.

Příště budeme pokračovat v popisu syntaxe LINQu, podíváme se na dotazy přes více kolekcí.


 

  Aktivity (1)

Článek pro vás napsal David Čápka
Avatar
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (11 hlasů) :
4.727274.727274.727274.727274.72727


 


Miniatura
Všechny články v sekci
Kolekce v C# .NET a LINQ
Miniatura
Následující článek
LINQ operátory 1

 

 

Komentáře

Avatar
Atrament
Člen
Avatar
Atrament:

Zdravím, neměly by být ty příklady v podkapitolce orderby takto?:

var dotaz = from u in uzivatele
            where (u.Vek > 15)
            orderby u.Jmeno
            select u;

klíčové je to select, kde bych čekal jenom u a ne ne u.Vek... Nebo jsem něco nepochopil?

 
Odpovědět 26.2.2015 13:55
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Atrament
David Čápka:

Vybrat celého uživatele je asi logičtější než vybrat jeho věk, ale na dotazu jako takovém nic špatného není.

Odpovědět 26.2.2015 14:49
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
forcabarca
Člen
Avatar
forcabarca:

V tomto dílu LINQ je velmi na škodu, že ty použité příklady nejde zkopírovat a spustit, a vážně se mi nechce vymýšlet kolekce třeba k příkladu toho groupingu, takže to bohužel musím sehnat a pochopit jinde než tady.

 
Odpovědět 7. ledna 20:03
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 3 zpráv z 3.