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

7. diel - LINQ v C # - revolúcia v dotazovanie

V minulej lekcii, Front a zásobník v C # .NET , sme sa venovali kolekciám front a zásobník. V dnešnom C# .NET tutoriálu sa zameriame na technológii LINQ, ktorá predstavuje súbor nástrojov pre dotazovanie sa na dáta. Jedná sa o veľmi revolučnú technológiu, ktorá prácu s akýmikoľvek dátami zjednodušuje a zovšeobecňuje.

Motivácia

Určite sme všetci doteraz pracovali s rôznymi typmi kolekciou rôznym spôsobom. Inak sme hľadali prvok v poli, inak sme čítali dáta z XML súboru a inak by sme hľadali používateľa v databáze. Predstavte si ale, keby existoval jeden unifikovaný spôsob, akým sa na dáta pýtať. Keby sme mohli ten istý dotaz spustiť ako na obyčajnom poli, tak na XML súboru alebo databázu. Asi tušíte, že LINQ nám poskytuje presne taký komfort. Ide o obrovskú abstrakcii, ktorá je vykúpená iba zanedbateľným znížením výkonu a ktorá vyhnala programovanie v C# do nových výšin.

LINQ ako jazyk

LINQ je pomerne sofistikovaná a rozsiahla technológie. Jej názov pochádza z anglického Language Integrated Query. Ako názov napovedá, jedná sa o dotazovací jazyk, ktorý je integrovaný priamo do syntaxe jazyka C #. Je teda jeho súčasťou a to od C# 3.0 a .NET frameworku 3.5. Od novších verzií beží dokonca na viacerých vláknach, čo zvyšuje efektivitu tejto technológie.

LINQ je veľmi podobný jazyku SQL a je to teda jazyk deklaratívny. Programu oznámime čo hľadáme a už nás veľmi nezaujíma, akým spôsobom pre nás dáta naozaj vyhľadá. Výhodou integrácie LINQ do C# je kontrola syntaxe dotazov pri preklade programu.

Urobme si malý príklad, ako pôjdeme ďalej. Založte si nový projekt, pôjde o konzolovú aplikáciu s menom LINQ. Vytvoríme si jednoduché poľa textových reťazcov.

string[] jmena = {"David", "Martin", "Dan", "Petr", "Vratislav", "Eliska"};

Teraz si pomocou LINQ dotazu z tohto poľa vyberieme tie položky, ktorých dĺžka je väčšia ako 5 písmen. Do programu zapíšte nasledujúci kód:

var dotaz = from j in jmena
            where (j.Length > 5)
            select j;

Otázka nápadne pripomína SQL, tí ktorí ho poznajú majú výhodu. Myslím, že SQL nad poľom ste ešte nevolali, že? :) Hneď si otázku podrobne popíšeme, najprv ale dokonca náš program a to tým, že si výsledok dotazu vypíšeme do konzoly:

// výpis výsledku
foreach (string jmeno in dotaz)
{
    Console.WriteLine(jmeno);
}
Console.ReadKey();

Výstup programu:

Ukážka použitia LINQ dotazu v C# .NET - Kolekcia v C # .NET a LINQ

Ako vyzerá dotaz

Vráťme sa k nášmu dotazu, ktorý vyzeral takto:

var dotaz = from j in jmena
            where (j.Length > 5)
            select j;

Znalci SQL budú určite prekvapení, že je dotaz pospiatky. Má to svoje opodstatnenie, ku ktorému dôjdeme.

Najprv určujeme odkiaľ budeme dáta vyberať, slúži na to kľúčové slovo from. Za from nasleduje premenná, ktorá bude vo zvyšku dotaze reprezentovať prvok z kolekcie. Ďalej nasleduje kľúčové slovo in a samotná kolekcie. Je to podobné ako u cykle foreach. Otázky sa píšu na niekoľko riadkov, aby boli prehľadnejšie. To oceníte najmä u tých zložitejších.

Pre opodmínkování môžeme uviesť riadok s kľúčovým slovom where, za ním nasleduje podmienka. Podmienky v tomto prípade píšeme úplne rovnako, ako sme to robili doteraz.

Na poslednom riadku nasleduje kľúčové slovo select, pomocou ktorého určíme čo vyberáme. Tu vyberáme celý prvok z kolekcie, teda j. Rovnako tak by sme ale mohli vybrať napríklad len jeho dĺžku j.Length alebo čokoľvek iné.

Kľúčové slovo var

Otázka ukladáme do premennej typu var, s týmto typom sme sa ešte nestretli a vlastne to ani dátový typ nie je. Kľúčové slovo var nám umožňuje prenechať výber dátového typu na kompileru (rozumejte, že ho za nás priradí C# sám pri preklade). Teoreticky by sme var mohli použiť aj inokedy, napr. Nasledovne:

var s = "C# pozná že toto je string a dá proměnné s typ string";
var i = 10;

Kód vyššie C# preloží v podstate na toto:

string s = "C# pozná že toto je string a dá proměnné s typ string";
int i = 10;

Kľúčové slovo var teda umožňuje určiť typ údajov až pri preklade programu a vlastne nás od dátového typu odtieňuje. V bežných programoch by bolo var naobtíž, pretože špecifikácia typov má svoj zmysel. Typy teda budeme písať ďalej a v žiadnom prípade ich nenahrádzajte slovom var, ako sa to niektorí začiatočníci úplne chybne naučí.

Kľúčové slovo var bolo zavedené kvôli LINQ a to z troch dôvodov:

  • Po prvé sú dátové typy otázok pomerne zložité a bolo by komplikované je vždy explicitne špecifikovať.
  • Po druhé keď zmeníme typ kolekcie, zmení sa aj typ otázky, čo by vyžadovalo zbytočnú editáciu kódu a znížilo všeobecnosť technológie.
  • Po tretie s LINQ prichádza tzv. Anonymné typy, u ktorých sa bez var nezaobídeme, čoskoro sa k nim dostaneme.

Čo si pamätajte je, že var má svoje miesto hlavne v dotazoch a v bežnom kóde by sa nemal príliš vyskytovať, aj keď by sa tam teoreticky dalo použiť.

Všeobecne platí poučka, že var môžeme použiť v prípade, že zjednoduší deklaráciu a pritom je stále jasné akého typu premenná je. Ukážme si 4 príklady bez var as var:

int a = 10;
List<Dictionary<string, string>> slovniky = new List<Dictionary<string, string>>();
IOrderedQueryable<Uzivatel> prazane = from u in db.Uzivatele
                                      where u.Mesto == "Praha"
                                      orderby u.Jmeno
                                      select u;
int b = a;

Pomocou var môžeme kód upraviť takto:

var a = 10;
var slovniky = new List<Dictionary<string, string>>();
var prazane = from u in db.Uzivatele
              where u.Mesto == "Praha"
              orderby u.Jmeno
              select u;
var b = a;

U prvej premennej nám var neprinesie žiadne zjednodušenie. U generického listu generických slovníkov sa jeho použitia naopak oplatí a keďže z pravej strany priradenie aj vidíme akého typu je premenná slovniky, var je tu aj dobrou voľbou. Rovnako by ale bolo čistejšie napísať na niečo podobné triedu, ukladať kolekcia kolekcií je skôr zlá praktika. U LINQ dotazu je typ zložitý a keby sme napr. Zmazali orderby, zmenil by sa na IQueryable<Uzivatel>. Takto nemusíme nad typom premýšľať a ani ho meniť spolu s otázkou. Posledný použitia var je odstrašujúci, vôbec z riadky nespoznáme čo do premennej b ukladáme.

Ďalšou častou chybou je, že si ľudia myslia, že var deklaruje premennú dynamického typu, teda že do nej môžeme uložiť čo chceme. Nie je tomu tak, typ sa napevno určí pri preklade a počas programu ho nemožno meniť. Kód nižšie teda nebude fungovať:

// tento kód nebude fungovat
var promenna = "Teď tam je text";
promenna = 10; // Teď tam je číslo

Program vyššie vytvorí premennú typu string a potom spadne, pretože sa do typu string snažíme uložiť int.

Pod pokrievkou

Ako že to celé funguje? Keď sa pozriete na začiatok vášho zdrojového kódu, uvidíte, že obsahuje nasledujúce using:

using System.Linq;

Ten je přednačtený u všetkých typov projektov. Skúsme ho zakomentovat, v tej chvíli nám Visual Studio podčiarkne v dotaze premennú jmena.

LINQ funguje pomocou tzv. Providerov, tých je niekoľko typov a je aj možné si definovať vlastné. My teraz používame LINQ To Objects, ktorý je implementovaný práve v mennom priestore System.Linq a ktorý rozšíri obyčajné kolekcie ako sú napr. Polia a listy o ďalšie metódy navyše. Pod pokrievkou sú teda rozširujúce metódy.

Skúsme si teraz (ešte sa zakomentovaným using em) vyvolať ponuku metód na našom poli. Napíšme jmena. (jmena a bodku)., Aby sme vyvolali zoznam metód na poli:

Obyčajné metódy na poli v C# .NET - Kolekcia v C # .NET a LINQ

Teraz riadok opäť odkomentujte a urobme to isté znova:

Linq metódy na poli v C# .NET - Kolekcia v C # .NET a LINQ

Na obyčajnom poli máme naraz kvantum nových metód. Keď C# vykonáva LINQ dotaz, volá na pozadí na kolekciu tieto metódy. Tie sú riešené cez lambda výrazy, ktoré sme už stretli v OOP kurze.

Náš otázka:

var dotaz = from j in jmena
            where (j.Length > 5)
            select j;

teda C# prežuje a vygeneruje nasledujúci kód:

var dotaz = jmena.Where(j => j.Length > 5).Select(j => j);

Môžete si vyskúšať, že otázka bude fungovať rovnako. Máme možnosť s LINQ pracovať aj takto, ale pomocou SQL-like zápisu je to oveľa stráviteľnejšie. Mimochodom, práve sme si vysvetlili, prečo je v dotaze najprv where a až potom select. Dáta sa musí najprv nájsť metódou Where() az výsledku sa až potom označí čo nás zaujíma metódou Select(). Dôvodom je teda postupnosť metód pod pokrievkou technológie.

Na záver si prezraďme, na čo sa v našom prípade preložia onen záhadný typ var. Výsledný typ otázky na našom poli je:

System.Linq.Enumerable.WhereArrayIterator<string>

Keďže nemôžeme z hlavy vedieť aký typ LINQ zrovna vráti (presnejšie povedané by sme od toho mali byť odtienené), bol zavedený typ var, ako už bolo povedané vyššie.

V budúcej lekcii, LINQ provideri, anonymné typy, radenie a zoskupovanie , budeme pokračovať v dopytovania.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 578x (23.17 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Predchádzajúci článok
Front a zásobník v C # .NET
Všetky články v sekcii
Kolekcia v C # .NET a LINQ
Preskočiť článok
(neodporúčame)
LINQ provideri, anonymné typy, radenie a zoskupovanie
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
1 hlasov
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 sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity