2. DataSet

DataSet představuje reprezentaci vázaných dat "offline" v paměti. Jeho výhoda tedy je, že všechna data jednou načte, a pak už nic nenačítá z databáze.

DataSet může obsahovat i více tabulek v něm reprezentovaných jako objekty DataTable. Může navíc definovat i vazby mezi těmito tabulkami a spoustu dalších možností. Celkově se tedy bere jako "úschovna dat", s kterou můžeme provádět velkou množinu operací.

Datový typ DataSet může být naplněn dvěma způsoby - z klasické databáze nebo ze souboru XML reprezentujícího databázi.

2.1. Typovaný vs. netypovaný DataSet

Existují dva způsoby, jak přistupovat k prvku DataSet.

Jedním z nich je vytvořit prvek DataSet odvozený od původní DataSet třídy, následně využít informace z XML schématu týkajícího se databáze, kde má být náš DataSet použit a vygenerovat novou třídu. Takto se tabulky, sloupce, relace apod. se generují do této třídy jako množina podtříd a vlastností. Tento způsob se nazývá typovaný dataset.

[znalosti]

Netypovaný DataSet oproti typovanému nepotřebuje žádné schéma. Obsahuje tabulky, sloupce a ostatní, ale tyto jsou přístupny pouze jako kolekce.

Následují příklady typovaného a netypovaného prvku DataSet.

[ukázka kódu]
// chceme z tabulky Zamestnanci ziskat prvni hodnotu sloupce s nazvem IDzam
// DataSet se nazyva dsZam
// typovany DataSet
string s = dsZam.Zamestnanci[0].IDzam;

// netypovany DataSet
string s = (string)dsZam.Tables("Zamestnanci").Rows[0]["IDzam"];

Z příkladu je patrné, že je daleko přehlednější použít typovaný DataSet. Visual Studio má pro typovaný DataSet podporu, jako je například IntelliSense (zobrazování možností při psaní kódu). Je také méně náchylný na chyby. Ovšem ne vždy budeme moci typovaný DataSet použít. Jedná se například o obecné použití prvku DataSet pro práci s různými daty.

Občas mohou nastat situace, kdy se neubráníme používání netypovaného DataSet, ale pokud je ta možnost, je typovaný DataSet doporučován. My v dalším budeme pracovat s typovanými prvky DataSet.

2.2. DataSet při získání dat z databázového serveru

U databázového serveru máme informace o tom, v jakém tvaru budou všechny tabulky a potřebná data. Proto pokud budeme chtít vytvořit nový DataSet tak, aby obsahoval přístup k datům z naší tabulky (tabulek), jednoduše opět poklepeme pravým tlačitkem myši na prvek dříve vložený prvek SqlDataAdapter. Ten se již nachází pod naším formulářem (Form) v návrhovém režimu (Design). Vybereme možnost Generate Dataset.

Obrázek 7.4. SqlDataAdapter - Generate DataSet

SqlDataAdapter - Generate DataSet

Pokud se po tomto kroku podíváme do seznamu tříd v našem projektu, všimneme si, že přibyla nová třída nesoucí název právě vloženého prvku DataSet. Obsahuje zároveň i potřebné metody a vlastnosti pro přístup k položkám tabulky test.

Na obrázku vidíme strukturu třídy DataSet1 vegenerovanou z SqlDataAdapteru na tabulku test. Mimo jiné se zde nachází třídy testDataTable a testRow (třídy jsou obvykle nazývámy velkým písmenem na začátku, nyní byl název ovlivněn názvem tabulky "test" s malým písmenem na počátku). testDataTable popisuje celou tabulku test, testRow popisuje jeden řádek tabulky. Názvy tříd jsou samy vysvětlující.

Obrázek 7.5. Automaticky vygenerovaná třída DataSet1

Automaticky vygenerovaná třída DataSet1

DataSet je z databáze možno vygenerovat i druhým způsobem, a to pomocí XML schématu.

Pokud budeme chtít používat DataSet, musíme jej ještě před tím přes DataAdapter naplnit daty. Při napojení na databázový server zavoláme metodu SqlDataAdapter.Fill(DataSet).

[ukázka kódu]
... 
myDataAdapter.Fill(myDataSet); 
...

DataSet myDataSet můžeme naplnit i z více DataAdapterů. Záleží na tom, jak (a zda) máme vytvořeno schéma databáze.

2.3. DataSet při získání dat z XML souboru

Předpokládejme nyní, že databázi máme uloženou v XML souboru. Abychom ji mohli načíst do prvku DataSet, je třeba pro ni nejprve vytvořit (či načíst) XML schéma umožňující při automatické generaci vytvořit podtřídy a metody potřebné pro práci s tabulkami.

2.3.1. Vytvoření XML schématu

Pro vytvoření nového schématu provedeme volbu z menu: Project -> Add New Item (popř. Existing Item, pokud schéma již máme někde vytvořeno).

Objeví se prázdná plocha s textem oznamujícím způsob vytvoření nového schématu. Zde můžeme postupným vkládáním elementů vytvořit strukturu podobně jako v databázi. Můžeme také vytvořit stejné schéma, jaké se nachází v naší databázi. Jednoduše přetáhneme ze Server Exploreru - volby Data Connections naše tabulky na plochu. Doplníme vazby mezi tabulkami, pokud je to nutné.

Obrázek 7.6. Databázové schéma

Databázové schéma

Pokud se nacházíme v okně s návrhem XML schématu, podobně jako u SqlDataAdapteru můžeme vygenerovat DataSet. Zde se to provádí zaškrtnutím volby z menu: Schema -> Generate DataSet. Tato volba nám při každém uložení schématu generuje DataSet.

Pokud jsme vytvořili XML schéma přetáhnutím tabulky ze Server Exploreru, vytvoříme shodný prvek DataSet jako v předchozím případě (pouze s jiným názvem).

Můžeme si zobrazit zdrojový XML kód poklepáním na záložku XML nacházející se pod oknem se schématem.

Obrázek 7.7. Možnost generace DataSet, záložka XML

Možnost generace DataSet, záložka XML

2.3.2. Naplnění prvku DataSet z XML souboru

Nyní, když máme vytvořeno databázové schéma, můžeme bez problému načíst data. Protože při práci s XML daty reprezentujícími databáze nepotřebujeme DataAdapter, volá se metoda prvku DataSet.ReadXml(). Jako parametr této metody uvedeme název XML souboru s našimi daty.

2.4. Práce s daty v prvku DataSet

Nyní máme data načtena do prvku DataSet. V této chvíli s nimi můžeme zacházet, jak se nám zlíbí. Můžeme i použít přístup k datům jako u netypovaného prvku DataSet. Jak už ale bylo zmíněno výše, typovaný DataSet nachází ve Visual Studiu lepší podporu.

2.4.1. Vybírání (hledání) dat v DataSet

Je spousta prostředků, jak data z prvku DataSet vybrat. Můžeme vyhledat jednotlivou položku v celém DataSet nebo jej celý můžeme jednoduše zobrazit pomocí prvku Windows.Forms.DataGrid. Samozřejmě nyní hovoříme o grafickém režimu. V klasickém konzolovém výstupu bychom museli pravděpodobně většinu dat pracně vypisovat.

2.4.1.1. DataGrid

Pro hromadný výpis dat nám mimo jiné velice dobře poslouží nástroj DataGrid. Nalezneme jej opět v Toolboxu pod oddílem Windows Forms. Po přetáhnutí DataGrid do formuláře si zobrazíme jeho vlastnosti a zaměříme se v nich na oddíl Data, možnost DataSource.

Obrázek 7.8. DataSource u nástroje DataGrid

DataSource u nástroje DataGrid

Pokud máme vytvořený DataSet, můžeme právě zde přiřadit, která data si DataGrid načte. Do nástroje DataGrid můžeme vložit samostatnou tabulku z prvku DataSet nebo celý DataSet. V druhém případě se nám při spuštění programu objeví v nástroji DataGrid nejprve políčko plus. Po rozbalení se objeví seznam tabulek, ve kterých se už naviguje pomocí odkazů. Pokud v jednotlivých tabulkách máme definovány vazby na jiné tabulky, objeví se tyto vazby u každého řádku tabulky (opět políčko plus).

Data uložená v DataGridu můžeme různě upravovat i přidávat nová a mazat existující. Jelikož je náš DataGrid napojen přímo na náš DataSet, mohli bychom přímo změny takto vzniklé uložit do prvku DataSet a ty by se následně po uložení DataSetu projevily ve výsledné databázi.

2.4.1.2. Přístupy k jednotlivým datům

Určitě je zapotřebí získat i jednotlivá data vztahující se k určité položce. Pro tento případ slouží metoda Select() prvku DataSet. Jestliže máme typovaný DataSet, můžeme tuto metodu reprezentující SQL dotaz provést přímo na určitou tabulkou v prvku DataSet.

V příkladu je prvek dataSetHudba1 naplněn třemi tabulkami SONG, AUTOR, ALBUM. Tabulky jsou spojeny vazbami AUTORSONG, ALBUMSONG. V názvech vazeb je na prvním místě tabulka rodičovská (v ní se nachází primární klíč) a na druhém potomek (pracuje se s cizím klíčem). Budeme například chtít vybrat autora písně s názvem Chorale.

[ukázka kódu]
DataRow[] autor;
autor = dataSetHudba1.SONG.Select("name = 'Chorale' AND Parent.(AUTORSONG).ID_autor=ID_autor");
// na konzole se zobrazi jmeno autora z databaze - Adiemus
System.Console.WriteLine(autor[0].GetParentRow("AUTORSONG")["name"].ToString());

S příkazem SELECT se jistě většina setkala, nebudeme se jím tedy vice zabývat. Více o něm v jazyce C# je možno se dočíst na stránkách http://msdn.microsoft.com.

2.4.2. Úprava dat v DataSet

2.4.2.1. Změna dat

Jak bylo ukázáno v porovnání mezi typovaným a netypovaným prvkem DataSet, lze přistupovat k jednotlivým položkám tabulek pomocí názvu tabulek, indexu řádky a názvu sloupce. Stejným způsobem lze data na tomto umístění i měnit. Existuje celá řada dalších způsobů, jejichž objevování nechám na každém zvlášť.

2.4.2.2. Smazání dat

Smazání dat lze provést podobně jako v předchozím případě při změně údajů pouze s tím rozdílem, že nyní mažeme celý řádek, tedy pokud budeme chtít smazat první řádek tabulky SONG, provedeme to pomocí metody Delete().

[ukázka kódu]
... 
dataSetHudba1.SONG[0].Delete(); 
...

2.5. Uložení dat z prvku DataSet

Všechna data jsou nyní zpracována a aby zůstaly nové změny zachovány, v současné chvíli musíte uložit data v prvku DataSet. Ať již se jedná o uložení na databázový server či přímo do XML souboru, provádí se vše velice jednoduše.

2.5.1. Uložení na databázový server

Pokud používáme data z databázového serveru, mějme na paměti, že DataSet zde spolupracuje s DataAdapterem. DataAdapter naplnil náš DataSet. Také DataAdapter bude aktualizovat data v databázi. Mějme například SqlDataAdapter SqlDataAdapterSong, který se stará o práci s tabulkou SONG. My pracujeme s prvkem DataSet s názvem dataSetHudba1.

[ukázka kódu]
SqlDataAdapterSong.Update(dataSetHudba1);

Uloženo.

2.5.2. Uložení do XML souboru

Pokud jsme data načítali z XML souboru a chceme je opět uložit do souboru (což není nezbytně nutné, tato data lze uložit v kterékoliv vhodné databázi), prvek DataSet nám poslouží i nyní. Stejně, jako jsme provedli načtení XML dat, provedeme i zápis. Opět předpokládejme DataSet s názvem dataSetHudba1.

[ukázka kódu]
string filename = "music_collection.xml"; 
... 
dataSetHudba1.WriteXml(filename);