IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 8 - LINQ provideři, anonymní typy, řazení a seskupování

V minulé lekci, LINQ v C# .NET - Revoluce v dotazování, jsme si uvedli technologii LINQ a vytvořili svůj první jednoduchý dotaz.

Dnes budeme v C# .NET tutoriálu 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 .NET

Některé providery dodává Microsoft přímo v .NET frameworku, nás budou zajímat zejména 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/LINQ to Entities - Provider mapuje LINQ příkazy na SQL dotazy a umožňuje nám pracovat s MS-SQL databází. Provider nám poskytuje tzv. ORM (Object-relation mapping, viz další díly kurzu). Práce s databází je plně objektová, v kurzech budeme často pracovat s providerem LINQ to Entities, LINQ to SQL je jeho předchůdce. Linq to Entities je součástí tzv. Entity frameworku, což je poměrně rozsáhlá knihovna pro práci s relačními (databázovými) daty.
  • 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. Nicméně, někteří z nich nejsou příliš dobře podporováni a je velmi dobrý nápad držet se spíše Microsoft technologií.

  • 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 dalších kurzech se budeme věnovat LINQ to XML a LINQ to Entities.

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í:

Konzolová aplikace
Anonym
Anonymní
18

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íme 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é účely, 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, abychom 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 LINQ.

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;
class Osoba
{
    public string Jmeno { get; private set; }
    public string Prijmeni{ get; private set; }
    public int Vek { get; private set; }

    public Osoba(string jmeno, string prijmeni, int vek)
    {
        Jmeno = jmeno;
        Prijmeni = prijmeni;
        Vek = vek;
    }

    public override string ToString()
    {
        return Jmeno + " " + Prijmeni;
    }

}

Výstup:

Konzolová aplikace
24
18
40
24

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 klauzule z LINQ mají své metody, to bylo jen pro upomenutí, dále již nebudu "metodovou" verzi u ukázek 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;
class Osoba
{
    public string Jmeno { get; private set; }
    public string Prijmeni{ get; private set; }
    public int Vek { get; private set; }

    public Osoba(string jmeno, string prijmeni, int vek)
    {
        Jmeno = jmeno;
        Prijmeni = prijmeni;
        Vek = vek;
    }

    public override string ToString()
    {
        return Jmeno + " " + Prijmeni;
    }

}

Výstup:

Konzolová aplikace
24
40
18
24

V původním příkladu jsme mohli použít ascending, ale není to nutné. Pokud jde o metody, použije se OrderByDescending().

Ř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;
class Osoba
{
    public string Jmeno { get; private set; }
    public string Prijmeni{ get; private set; }
    public int Vek { get; private set; }

    public Osoba(string jmeno, string prijmeni, int vek)
    {
        Jmeno = jmeno;
        Prijmeni = prijmeni;
        Vek = vek;
    }

    public override string ToString()
    {
        return Jmeno + " " + Prijmeni;
    }

}

Výsledek:

Konzolová aplikace
24
18
40
24

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

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

group-by (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);
}

class Osoba
{
    public string Jmeno { get; private set; }
    public string Prijmeni{ get; private set; }
    public int Vek { get; private set; }

    public Osoba(string jmeno, string prijmeni, int vek)
    {
        Jmeno = jmeno;
        Prijmeni= prijmeni;
        Vek = vek;
    }
}

Dotaz vybere:

Konzolová aplikace
15
Karel
24
Josef
Simona
13
Jan
18
Marie
14
Michaela

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

V následujícím kvízu, Kvíz - Slovníky, množiny, fronta, zásobník v C# .NET Kolekce, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.


 

Předchozí článek
LINQ v C# .NET - Revoluce v dotazování
Všechny články v sekci
Kolekce a LINQ v C# .NET
Přeskočit článek
(nedoporučujeme)
Kvíz - Slovníky, množiny, fronta, zásobník v C# .NET Kolekce
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
276 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity