Lekce 5 - SqlDataReader a připojená databáze v C# .NET
V předchozím kvízu, Kvíz - Databáze, přístupy, připojená aplikace v C#- ADO.NET , jsme si ověřili nabyté zkušenosti z předchozích lekcí.
V dnešním C# .NET tutoriálu se naučíme číst z databáze jednotlivé řádky.
Zpracování dat
Pokud potřebujeme spustit nad databází dotaz, který vrací více
záznamů (ten náš poslední vracel jen jedno číslo), musíme ke
zpracování výsledku dotazu využít třídu *DataReader
.
Instanci této třídy jako výsledek vrátí metoda
ExecuteReader()
třídy Command
. Třída
*DataReader
umožňuje procházet výslednou množinu dat po
jednotlivých záznamech. K tomu slouží metoda Read()
. Přístup
k jednotlivým atributům záznamu můžeme získat pomocí indexu nebo názvu
sloupce uvedeného v hranatých závorkách, případně pomocí metod
Get...()
, které nám hodnoty rovnou převedou na požadovaný
datový typ.
Příklad 4
Vypište na obrazovku všechna slovíčka. U slovíček budeme chtít vypsat
sloupce: Id
, Czech
a English
.
Řešení
SqlCommand prikaz = new SqlCommand("SELECT Id, Czech, English FROM Word", pripojeni); pripojeni.Open(); SqlDataReader dataReader = prikaz.ExecuteReader(); while (dataReader.Read()) // dokud neprojdeme všechny záznamy { Console.WriteLine("{0} {1} {2}", dataReader[0], // index sloupce (Id) dataReader["Czech"], // název sloupce dataReader.GetString(2)); // index sloupce (English) s převedením na požadovaný datový typ }
Výsledek:
Konzolová aplikace
1 počítač computer
2 míč ball
3 pes dog
4 já I
5 mít rád like
6 devbook devbook
SQL dotaz místo COUNT
nyní obsahuje výčet sloupců, které
vybíráme. SqlDataReader
čte řádek po řádku co databáze
vrátila a výsledky vypisuje do konzole.
Předávání parametrů
Udělejme z aplikace opravdový slovníček a nechme uživatele zadat slovíčko, které mu následně přeložíme.
SQL injekce
Nejprve si ukažme, jak se to nemá dělat. Naivně bychom si mohli nechat zadat slovíčko a to potom přímo vložit jako vyhledávanou frázi do dotazu. Zdrojový kód aplikace by vypadal takto:
// tento zdrojový kód je nebezpečný string connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=SlovickaDB;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 všechny záznamy { Console.WriteLine("Překlad: {0}", dataReader["Czech"]); } } Console.ReadKey();
SQL dotaz je podobný tomu předchozímu. Nezajímají nás však již
všechny řádky, ale jen ty, kde má sloupec English
určitou
hodnotu. Podmínku v SQL zapíšeme pomocí klauzule WHERE
.
Ačkoli se zdá, že aplikace funguje korektně:
Konzolová aplikace
Zadej anglické slovíčko k překladu
computer
Překlad: počítač
Zamyslete se nad tím, co se stane, když nějaký uživatel zadá k překladu tento řetězec:
'; DROP TABLE Word --
Škodlivý kód se nám vloží přímo do dotazu a spustí se nad databází. Útočníkovi tak dáváme plnou kontrolu and našimi daty, v tomto případě nám nenávratně vymaže celou tabulku. To je ještě poměrně nevinný útok, mohl by nám vzít i hesla uživatelů a podobně.
Předávání parametrů
Bezpečnostní problém způsobuje samozřejmě přímé vkládání hodnot do textu SQL dotazu. Útok se proto nazývá SQL injection, jako vložení cizího SQL kódu do našeho.
Platí zásada, že musíme počítat s tím, že škodlivý kód může být v každém parametru, který do dotazu vkládáme. Nelze se spolehnout na to, že tato proměnná asi nebude nic od uživatele obsahovat.
Aplikace se mění a do proměnné by se mohla časem dostat i třeba jen část hodnoty, kterou zadal uživatel. A věřte mi, že uživatelé jsou vynalézaví a budou naši aplikaci zkoušet a budou nám tam tyto hodnoty vkládat.
V minulosti se parametry ošetřovaly speciální funkcí, která tzv. zescapovala škodlivé znaky. Moderní dotazy se píší pomocí tzv. Prepared Statements. Ty fungují tak, že se do dotazu místo parametrů vloží jen speciální značky. Parametry se poté předávají odděleně. Ukažme si, jak do dotazu vložit parametry správně:
string connectionString = @"Data Source=(localdb)\MSSQLLocalDB;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); 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šimněte si, že v SQL dotazu je jen zástupná značka,
která se označuje zavináčem @
a libovolným názvem. Nepíšeme
kolem ní ani apostrofy, ty jsou dodány později podle typu značky. Před
zavoláním metody ExecuteReader()
do dotazu připojíme parametry,
v našem případě parametr @slovo
, jehož hodnotou bude
proměnná slovo. Databáze si sama parametry ošetří a nemusíme se bát, že
by nám aplikaci někdo mohl nabourat.
V příští lekci, Databáze v C# .NET - INSERT, UPDATE, DELETE a COUNT, si ukážeme, jak záznamy v databázi přidávat, mazat a editovat. Zdrojové kódy dnešního programu jsou jako vždy v příloze ke stažení.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 455x (1.03 MB)
Aplikace je včetně zdrojových kódů v jazyce C#