Pouze tento týden sleva až 80 % na e-learning týkající se C# .NET
Využij akce až 80% zdarma při nákupu e-learningu. Více informací .
BF summer

5. diel - SqlDataReader a pripojené databázy v C # .NET

V minulej lekcii, Pripojená databázová aplikácia v C # .NET , sme sa pripojili k databáze a vypísali počet riadkov v tabuľke. V dnešnom C# .NET tutoriálu sa naučíme čítať z databázy jednotlivé riadky.

Spracovanie dát

Ak potrebujete spustiť nad databázou dotaz, ktorý vracia viac záznamov (ten vyššie vracal len jedno číslo), musíte na spracovanie výsledku otázky využiť triedu *DataReader. Inštanciu tejto triedy ako výsledok vráti metóda ExecuteReader() triedy Command. Trieda *DataReader umožňuje prechádzať výslednú množinu dát po jednotlivých záznamoch. K tomu slúži metóda Read(). Prístup k jednotlivým atribútom záznamu môžete získať pomocou indexu alebo názvu stĺpca uvedeného v hranatých zátvorkách, prípadne pomocou metód Get...(), ktoré vám hodnoty rovno prevedú na požadovaný dátový typ.

Príklad 4

Vypíšte na obrazovku všetky slovíčka. U slovíčok budeme chcieť vypísať stĺpce: Id, Czech a English.

Riešenie

SqlCommand prikaz = new SqlCommand("SELECT Id, Czech, English FROM Word", pripojeni);
pripojeni.Open();
SqlDataReader dataReader = prikaz.ExecuteReader();
while (dataReader.Read()) // dokud neprojdeme vsechny zaznamy
{
    Console.WriteLine("{0} {1} {2}",
        dataReader[0],                      // index sloupce (Id)
        dataReader["Czech"],                // nazev sloupce
        dataReader.GetString(2));           // index sloupce (English) s prevedenim na pozadovany datovy typ
}

výsledok:

Výpis riadkov z databázy v C# .NET

SQL dotaz miesto COUNT teraz vymenováva stĺpcov, ktoré vyberáme. Reader číta riadok po riadku čo databázy vrátila a výsledky vypisuje do konzoly.

Odovzdávanie parametrov

Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!

Urobme z aplikácie naozajstný slovníček a nechajme používateľa zadať slovíčko, ktoré mu následne preložíme.

Sql injekcie

Najprv si ukážme, ako sa to nemá robiť. Naivne by sme si mohli nechať zadať slovíčko a to potom priamo vložiť ako vyhľadávanou frázu do dotazu. Zdrojový kód aplikácie by vyzeral takto:

// tento zdrojový kód je nebezpečný
string connectionString = @"Data Source=localhost\MSSQLSERVER2008;Initial Catalog=SlovnicekDB;Integrated Security=True";
using (SqlConnection pripojeni = new SqlConnection(connectionString))
{
    pripojeni.Open();

    Console.WriteLine("Zadej anglické slovíčko k překladu");
    string slovo = Console.ReadLine();

    SqlCommand prikaz = new SqlCommand("SELECT Czech FROM Word WHERE English='" + slovo + "'", pripojeni);

    SqlDataReader dataReader = prikaz.ExecuteReader();
    while (dataReader.Read()) // dokud neprojdeme vsechny zaznamy
    {
        Console.WriteLine("Překlad: {0}", dataReader["Czech"]);
    }
}
Console.ReadKey();

SQL dotaz je podobný tomu predchádzajúcemu. Nezaujímajú nás však už všetky riadky, ale len tie, kde má stĺpec English určitú hodnotu. Podmienku v SQL zapíšeme pomocou klauzuly WHERE.

Hoci sa zdá, že aplikácia funguje korektne:

Vyhľadávanie v databáz v C# ADO .NET

Zamyslite sa nad tým, čo sa stane, keď nejaký používateľ zadá na preklad tento reťazec:

'; DROP TABLE Word --

Škodlivý kód sa nám vloží priamo do dotazu a spustí sa nad databázou. Útočníkovi tak dávame plnú kontrolu and našimi dátami, v tomto prípade nám nenávratne vymaže celú tabuľku. To je ešte pomerne nevinný útok, mohol by nám zobrať aj heslá používateľov a podobne.

Odovzdávanie parametrov

Bezpečnostný problém spôsobuje samozrejme priame vkladanie hodnôt do textu SQL dotazu. Útok sa preto nazýva SQL injection, ako vloženie cudzieho SQL kódu do nášho. Platí zásada, že musíme počítať s tým, že škodlivý kód môže byť v každom parametri, ktorý do dotazu vkladáme. Nemožno sa spoľahnúť na to, že táto premenné asi nebude nič od užívateľa obsahovať. Aplikácia sa mení a do premennej by sa mohla časom dostať aj napríklad len časť hodnoty, ktorú zadal používateľ. A verte mi, že užívatelia sú vynaliezaví a budú vašu aplikáciu skúšať a budú vám tam tieto hodnoty vkladať.

V minulosti sa parametre ošetrovali špeciálnou funkciou, ktorá tzv. Zescapovala škodlivé znaky. Moderné otázky sa píšu pomocou tzv. Prepared Statements. Tie fungujú tak, že sa do dopytu namiesto parametrov vloží len špeciálne značky. Parametre sa potom odovzdávajú oddelene. Ukážme si, ako do dotazu vložiť parametre správne:

string connectionString = @"Data Source=localhost\MSSQLSERVER2008;Initial Catalog=SlovnicekDB;Integrated Security=True";
using (SqlConnection pripojeni = new SqlConnection(connectionString))
{
    pripojeni.Open();

    Console.WriteLine("Zadej anglické slovíčko k překladu");
    string slovo = Console.ReadLine();

    SqlCommand prikaz = new SqlCommand("SELECT Czech FROM Word WHERE [email protected]", pripojeni);
    prikaz.Parameters.AddWithValue("@slovo", slovo);

    SqlDataReader dataReader = prikaz.ExecuteReader();
    while (dataReader.Read()) // dokud neprojdeme vsechny zaznamy
    {
        Console.WriteLine("Překlad: {0}", dataReader["Czech"]);
    }

}
Console.ReadKey();

Všimnite si, že v SQL dotaze je len zástupná značka, ktorá sa označuje zavináčom a ľubovoľným názvom. Nepíšeme okolo nej a apostrof, tie sú dodané neskôr podľa typu značky. Pred zavolaním metódy ExecuteReader() do dotazu pripojíme parametre, v našom prípade parameter @slovo, ktorého hodnotou bude premenná slovo. Databáza si sama parametre ošetrí a nemusíme sa báť, že by nám aplikácii niekto mohol nabúrať.

V budúcej lekcii, Databázy v C # .NET - INSERT, UPDATE, DELETE a COUNT , si ukážeme, ako záznamy v databáze pridávať, mazať a editovať. Zdrojové kódy dnešného programu sú ako vždy v prílohe k stiahnutiu.


 

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é 378x (1.03 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Predchádzajúci článok
Pripojená databázová aplikácia v C # .NET
Všetky články v sekcii
Databázy v C # - ADO.NET
Článok pre vás napísal JOF
Avatar
Ako sa ti páči článok?
Ešte nikto nehodnotil, buď prvý!
Aktivity (1)

 

 

Komentáre

Avatar
Michal Štěpánek:24.4.2014 18:02

Nevím jak to udělat v C#, ale ve VB.NET je to např. takto

//Naplnění Comboboxu CB_Zakazky - název firma a město
        Dim dt As DataTable = New DataTable     //tabulka s daty v paměti
        oledbcon.Open() //připojovací řetězec
        Dim strSql As OleDbCommand
        strSql = New OleDbCommand("SELECT Id, CisloZakazky + ' - ' + NazevZakazky AS Zakazka FROM TabulkaZakazky", oledbcon)
        Dim ada As New OleDbDataAdapter(strSql)
        ada.Fill(dt)

        With Me.CB_Zakazky
            .DataSource = dt
            .DisplayMember = "Zakazka"
            .ValueMember = "Id"
        End With
        oledbcon.Close()
Editované 24.4.2014 18:03
Odpovedať
24.4.2014 18:02
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
JOF
Lektor
Avatar
JOF:24.4.2014 22:45

Jak píše čočkin - u comboboxu nepoužívej vlastnost Text, ale Items apod.
Např. comboBox1.Item­s.Add(dataRea­der["Kod"].ToS­tring());
(Jinak vřele doporučuji komponenty pořádně pojmenovávat a nenechávat jméno comboBox1, comboBox2 atd.)

Co se týká připojení comboboxu na nějaký datový zdroj, tak to je možné u odpojeného přístupu ...

 
Odpovedať
24.4.2014 22:45
Avatar
Odpovedá na JOF
Michal Štěpánek:25.4.2014 8:11

Ano, připojení ComboBoxu na datový zdroj se dělá u odpojeného přístupu, ale myslím si, že stálé připojení na databázi je k ničemu, jen to zbytečně zvyšuje nároky na aplikaci, potažmo na síť, nehledě k tomu, že když aplikaci využívá více lidí najednou, je pak jednodušší ohlídat, aby si vzájemně "nepřekáželi". Spojení do DB by mělo být otevřeno jen po dobu nezbytně nutnou k provedení příkazu, jinak by mělo být zavřeno.

Odpovedať
25.4.2014 8:11
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Odpovedá na Michal Štěpánek
Marian Benčat:26.12.2015 17:41

Připojení do DB se ale ihned po ukončení usingu (případně close()) neukončuje. .NET si vnitřně všechny SQLConnection pooli a v okamžiku, kdy se zavolá Close() tak ho pouze navrátí zpět do connection poolu a ještě ho nějakou dobu nechává otevřené a pak ho recykluje. Stejný connection pool pak zjistí na základě connection stringu. Proto není také nutné nad SQL connection dělat vlastní pooling a ničemu nevadí na každý dotaz dělat new SQLConnection().. tedy ,,ničemu".

Odpovedať
26.12.2015 17:41
Totalitní admini..
Avatar
Odpovedá na Marian Benčat
Marian Benčat:26.12.2015 17:51

Je ale samozřejmě dobré tam ten connection ihned vracet, jakmile se daná operace dokončí.

Odpovedať
26.12.2015 17:51
Totalitní admini..
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!
Avatar
Karel Labonek:25.2.2018 15:24

Zdravím,
možná vzhledem k výše řečenému je to zbytečný dotaz, ale nějak mi v příkladech chybí uzavření připojení "pripojeni.Close()" s databází začínám tak jen pro jistotu :-) .

 
Odpovedať
25.2.2018 15:24
Avatar
jozef_i
Člen
Avatar
Odpovedá na Karel Labonek
jozef_i:25.2.2018 17:12

To sa vyriešilo použitím klauzuly "using" pre "pripojeni", po vyskočení z bloku using, a automaticky disposne....

 
Odpovedať
25.2.2018 17:12
Avatar
Odpovedá na jozef_i
Karel Labonek:26.2.2018 19:30

Jasné, děkuji za odpověď :-) .

 
Odpovedať
26.2.2018 19:30
Avatar
Marek Jakoubek:26.5.2020 21:40

Jestli bys chtěl o tomhle podrobnější informace, tak doporučuji zdejší článek o souborech: https://www.itnetwork.cz/…atch-finally
Sice se to netýká úplně databází, ale stejně :-) !

 
Odpovedať
26.5.2020 21:40
Avatar
jan široký
Člen
Avatar
jan široký:28.8.2020 12:18

Ahoj
dataReader po mne chce taky

dataReader.Close()

nebo uzivani v ramci using.

Editované 28.8.2020 12:18
 
Odpovedať
28.8.2020 12:18
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zatiaľ nikto nevložil komentár - buď prvý!