IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

8. diel - LINQ vo VB .NET - Revolúcia v dopytovaní

V minulej lekcii, Zásobník vo VB.NET , sme sa venovali kolekciu Zásobník.

V dnešnom VB .NET tutoriále sa zameriame na technológiu LINQ, ktorá predstavuje súbor nástrojov na dopytovanie sa na dáta. Ide o veľmi revolučnú technológiu, ktorá prácu s dátami zjednodušuje a zovšeobecňuje.

Motivácia

Určite sme všetci doteraz pracovali s rôznymi typmi kolekcií 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. Predstavme si, keby existoval jeden unifikovaný spôsob, akým sa na dáta pýtať.

Keby sme mohli tú istú otázku spustiť ako na obyčajnom poli, tak na XML súbore alebo databáze. LINQ nám poskytuje presne taký komfort. Jedná sa o obrovskú abstrakciu, ktorá je vykúpená iba zanedbateľným znížením výkonu a ktorá vyhnala programovanie v VB do nových výšin.

LINQ ako jazyk

LINQ je pomerne sofistikovaná a rozsiahla technológia. 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 VB. Je teda jeho súčasťou a to od VS 2008 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 VB je syntaktická kontrola otázok pri preklade programu.

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

Dim jmena() as String = {"David", "Martin", "Dan", "Peter", "Vroclav", "Eliška"}

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íšeme nasledujúci kód:

Dim dotaz As Object = 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, najskôr ale dokončíme náš program a to tým, že si výsledok otázky vypíšeme do konzoly:

        For Each jmeno As String In dotaz ' výpis výsledku
           Console.WriteLine(jmeno)
        Next
        Console.ReadKey()

Výstup programu:

Konzolová aplikácia
Martin
Vroclav
Eliška

Ako vyzerá otázka

Vráťme sa k našej otázke, ktorá vyzerala takto:
Dim dotaz As Object = From j In jmena
                      Where (j.Length > 5)
                      Select j

Znalci SQL budú určite prekvapení, že je otázka 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 dotazu reprezentovať prvok z kolekcie. Ďalej nasleduje kľúčové slovo In a samotná kolekcia. Je to podobné ako pri cykle For Each. Otázky je možné písať na niekoľko riadkov, aby boli prehľadnejšie. To oceníme najmä u tých zložitejších.

Pre opodmienkovanie 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 Object

Otázku ukladáme do premennej typu Object, s týmto typom sme sa ešte nestretli a vlastne to ani dátový typ nie je. Kľúčové slovo Object nám umožňuje prenechať výber dátového typu na kompiléri (rozumajme, že ho za nás priradí VB sám pri preklade). Teoreticky by sme Object mohli použiť aj inokedy, napr. takto:
Dim s = "VB pozná že toto je string a dá premenné s typ string"
Dim i = 10

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

Dim s as String = "VB pozná že toto je string a dá premenné s typ string"
Dim i as Integer = 10

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

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

  • dátové typy dotazov pomerne zložité a bolo by komplikované ich vždy explicitne špecifikovať.
  • keď zmeníme typ kolekcie, zmení sa aj typ dotazu, čo by vyžadovalo zbytočnú editáciu kódu a znížilo všeobecnosť technológie.
  • s LINQom prichádzajú tzv. anonymné typy, pri ktorých sa bez varov nezaobídeme, čoskoro sa k nim dostaneme.

Object má svoje miesto hlavne v dotazoch av bežnom kóde by sa nemal príliš vyskytovať, aj keď by sa tam teoreticky dalo použiť (napokon ak pri definícii premennej neuvedieme typ, defaultne sa priradí práve Object).

Všeobecne platí poučka, že Object 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 Object as Object:

Dim a As Integer = 10
Dim slovniky As New List(Of Dictionary(Of String, String))()
Dim prazane As IOrderedQueryable(Of Uzivatel) = From u In db.Uzivatele Where u.Mesto = "Praha" Order By u.Jmenou
Dim b As Integer = a

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

Dim a As Object = 10
Dim slovniky As Object = New List(Of Dictionary(Of String, String))()
Dim prazane As Object = From u In db.Uzivatele Where u.Mesto = "Praha" Order By u.Jmenou
Dim b As Object = a

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

Ďalšou častou chybou je, že si ľudia myslia, že Object 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 fungovať
Dim promenna As Object = "Teraz tam je text"

promenna = 10

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

Pod pokrievkou

Ako že to celé funguje? Keď sa pozrieme na začiatok nášho zdrojového kódu, uvidíme, že obsahuje nasledujúce Imports:
Imports System.Linq

Ten je prednačítaný pri všetkých typoch projektov. Skúsme ho zakomentovať, v tej chvíli nám Visual Studio podčiarkne v dotaze premennú jmena. V posledných verziách VB sa Linq pripája automaticky a Import netreba definovať. Našeptávač VS nám potom po napísaní bodky za meno premennej jmena vypíše množstvo nových metód:

Kolekcie a LINQ v VB.NET

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.

Na obyčajnom poli máme kvantum nových metód. Keď VB 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áš dotaz:

Dim dotaz As Object = From j In jmena
              Where (j.Length > 5)
                  Select j

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

    Dim dotaz As Object = jmena.Where(Function(j) j.Length > 5).[Select](Function(j) j)

Výstup:

Konzolová aplikácia
Martin
Vroclav
Eliská

Môžeme 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 otázke najprv Where a až potom Select. Dáta sa musia 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ží onen záhadný typ Object. Výsledný typ dotazu na našom poli je:

System.Linq.Enumerable.WhereArrayIterator(Of String)

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

V budúcej lekcii, LINQ vo VB.NET - Anonymné typy , sa naučíme deklarovať anonymné typy.


 

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é 4x (352.6 kB)
Aplikácia je vrátane zdrojových kódov v jazyku VB

 

Predchádzajúci článok
Zásobník vo VB.NET
Všetky články v sekcii
Kolekcie a LINQ v VB.NET
Preskočiť článok
(neodporúčame)
LINQ vo VB.NET - Anonymné typy
Článok pre vás napísal Přemysl Šíma
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
APSima
Aktivity