V závěrečné části našeho seriálu se zaměříme na třídy DataSet, DataAdapter, CommandBuilder a DataView.
Z obsahu:
- DataSet
- DataAdapter
- DataAdapter.Fill
- Práce s daty v DataSetu
- Vkládání nového řádku
- Úpravy řádek
- DataAdapter.Update
- CommandBuilder
- DataView
- Závěr
reklama
V závěrečné části našeho seriálu se zaměříme na třídy DataSet, DataAdapter, CommandBuilder a DataView.
Z obsahu:
- DataSet
- DataAdapter
- DataAdapter.Fill
- Práce s daty v DataSetu
- Vkládání nového řádku
- Úpravy řádek
- DataAdapter.Update
- CommandBuilder
- DataView
- Závěr
DataSet
Jedná se nejspíše o nejdůležitější třídu v ADO.NET, v podstatě je to databáze uložená v paměti. Tato databáze je především kolekcí třídy DataTable(přístupné přes vlastnost DataSet.Tables), která je jistou ekvivalencí tabulky v klasické databázi. Jednotlivé řádky tabulky jsou reprezentovány objekty DataRow, jejichž kolekce jsou přístupné vlastností Rows objektu DataTable a sloupce reprezentované objekty DataColumn jsou přístupně přes vlastnost DataTable.Columns. DataTable má rovněž vlastnosti Constrains podporující definování určitých omezení na jednotlivé sloupce tabulky. Relace mezi dvěma tabulkami v objektu DataSet můžete nadefinovat přidáním objektu DataRelation do kolekce DataSet.Relations.
DataSet se často používá pro ukládání výsledku nějakého dotazu z databáze. Samozřejmě nemusíte DataSet naplnit daty z databáze, stejně tak může být naplněn z XML souboru nebo vůbec nemusí být naplněn z externího zdroje, můžete si v něm sami vytvářet databázi úplně od začátku.
Na rozdíl od DataReader, který podporuje proudový pouze dopředný přístup, jen pro čtení, DataSet je celý uložen v paměti, takže umožňuje náhodný přístup k datům. Z tohoto důvodu se používá pro zkoumání a úpravy dat, které je následně schopen postoupit zpátky databázi z které data původně pocházejí.
DataSet se dále výborně hodí pro ukládání do mezipaměti na webových stránkách. Prostě se jednou za čas data z databáze uloží do DataSetu, který je uložen v mezipaměti, a při každém dotazu se místo čtení z databáze pouze přečtou data z paměti.
DataAdapter
Pokud chcete objekt DataSet naplnit daty z databáze, což bude nejspíše nejčastější způsob používání těchto objektů, sáhnete po třídě DataAdapter. DataSet sám s databází vůbec komunikovat neumí, k této práci používá prostředníka a tím je DataAdapter. Ten umí DataSet daty naplnit, ale i zpátky databázi podle změn v DataSetu aktualizovat.
DataAdapter sám je na rozdíl od DataSetu ve dvou variantách, SqlDataAdapter pro poskytovatele .NET SQL Serveru a OleDbDataAdapter pro poskytovatele .NET OLE DB.
Hlavní metodou DataAdapter jsou Fill a Update. Podívejme se na ně tedy blíže.
DataAdapter.Fill
Tento příklad ukazuje použití metody Fill.
SqlDataAdapter adapter = new SqlDataAdapter(
"select * from zamestnanci",
"server=localhost;database=mojeDatabaze;uid=sa;pwd=");
DataSet ds = new DataSet();
adapter.Fill(ds,"zamestnanci");
DataGrid.DataSource = ds;
DataGrid.DataBind();
Co tedy tento kód dělá?
Volání metody Fill otevře připojení k databázi pomocí řetězce připojení předaného konstruktoru SqlDataAdapter. Na tomto připojení se vykoná SQL dotaz z řetězce dotazu nainicializovaném voláním konstruktoru SqlDataAdapter. Z výsledku tohoto dotazu se zjistí jeho struktura a podle ní se vytvoří DataTable nazvaná zamestnanci v DataSetu ds. Tato tabulka se následně naplní všemi záznamy získanými SQL dotazem a otevřené připojení s databází se uzavře.
Následně se DataSet předá vlastnosti DataSource ovládacímu prvku DataGrid, ten po zavolání metody DataBind zobrazí výsledek.
Zde by bylo dobré zmínit, že pokud s tímto naplněným DataSetem neplánujete ještě dále pracovat, bylo by zde spíše lepší využít služeb třídy DataReader. Jelikož DataAdapter interně rovněž používá DataReader, bude následující kód dělat téměř to samé, co předchozí, s tím rozdílem, že je výkonnější, protože neponechává výsledek v paměti, který z ní následně musí odstraňovat garbage collector.
SqlConnection prip = new SqlConnection(
"server=localhost;database=mojeDatabaze;uid=sa;pwd=");
try
{
prip.Open();
SqlCommand prikaz = new SqlCommand(
"select * from zamestnanci",prip);
DataGrid.DataSource = prikaz.ExecuteReader();
DataGrid.DataBind();
}
catch(SqlException ex)
{
// Osetreni vyjimky
}
finally
{
prip.Close();
}
Jelikož je vlastnost DataSource typu object a jediné co musí tento zdroj dat splňovat je, aby implementoval rozhraní IEnumerable, proto nemusíte použít pouze DataSet, ale i DataReader. Samozřejmě i další kolekce, které implementují toto rozhraní(HashTable,Array,…)
Na těchto příkladech jsem použil pouze poskytovatele .NET SQL Serveru, ale pro přechod na .NET OLE DB opět stačí změnit předpony ze Sql na OleDb.
Práce s daty v DataSetu.
Předtím než se podíváme, jak změny provedené v DataSetu zpátky postoupit databázi, bychom si měli ukázat, jak se data v objektu DataSet dají měnit.
Když tedy chcete pracovat s daty v DataSetu, pracujete s objektem DataTable, který samotná data obsahuje.
Vkládání nového řádku
Následující kód přidá do tabulky DataTable nový řádek
DataTable tabulka = ds.Tables["zamestnanci"];
DataRow novy_radek = tabulka.NewRow();
novy_radek["jmeno"] = "Jan Okoun";
novy_radek["pozice"] = "sef";
novy_radek["adresa"] = "Nekde 12";
novy_radek["telefon"] = "555685";
novy_radek["plat"] = "45000"; tabulka.Rows.Add(novy_radek);
Všimněte si použití metody NewRow. Kdyby jste pouze vytvořili novou instanci DataRow přes new, nebyla by nainicializovaná odpovídajícím schématem tabulky a při přidání do seznamu řádek by nastala výjimka.
Vyhledávání řádek
Když lze do objektu DataTable data vkládat, jde je z něho samozřejmě i vytahovat. K tomu dobře poslouží metoda DataTable.Select.
DataRow[] radky = tabulka.Select("plat > 20000");
Zde se pole radky nainicializuje referencemi na objekty DataRow, které mají položku plat větší než 20000, z objektu DataTable tabulka. Nebudu zde popisovat syntaxi těchto výrazů, tu si můžete najít v dokumentaci SDK pro .NET Framework.
Úpravy řádek
Tímto polem můžete iterovat a položky měnit…
foreach(DataRow radek in radky)
radek["plat"] = (decimal)radek["plat"]+1000;
… nebo je mazat
foreach(DataRow radek in radky)
radek.Delete();
DataAdapter.Update
Když víme jak data v objektu DataSet měnit, ukažme si tedy, jak je zpátky postoupit databázi.
K tomuto účelu se volá tato metoda.
SqlDataAdapter adapter = new SqlDataAdapter("select * from zamestnanci",
"server=localhost;database=mojeDatabaze;uid=sa;pwd=");
DataSet ds = new DataSet();
adapter.Fill(ds,"zamestnanci");
SqlCommandBuilder stavitel = new SqlCommandBuilder(adapter);
//Vložení nového řádku
DataTable tabulka = ds.Tables["zamestnanci"];
DataRow novy_radek = tabulka.NewRow();
novy_radek["jmeno"] = "Jan Okoun";
novy_radek["pozice"] = "sef";
novy_radek["adresa"] = "Nekde 12";
novy_radek["telefon"] = "555685";
novy_radek["plat"] = "45000";
tabulka.Rows.Add(novy_radek);
//Postoupení změněných řádek zpátky do databáze
adapter.Update(ds);
Metoda Update si zjistí, které řádky byly v objektu DataSet změněny od poslední aktualizace databáze a ty pak vloží, odstraní nebo upraví v databázi. Jako argument nemusíte zadat DataSet, může jím být přímo jen určitá tabulka, kterou chcete aktualizovat.
Bylo by zde vhodné zmínit metodu DataSet.GetChanges, resp. DataTable.GetChanges. Ta vrátí objekt DataSet, resp. DataTable obsahující pouze řádky, které byly vloženy,změněny nebo smazány. Jaké řádky požadujete můžete určit argumentem DataRowState.
GetChanges nemusíte volat při každém volání metody Update, abyste aktualizovali změněná data. Metoda Update si sama umí zjistit jaké byly změny a pracuje pouze se změněnými řádky. GetChanges se však používá pokud chcete provést například odstranění některých řádek před vkládáním, aby nedošlo k duplicitě klíčů.
CommandBuilder
Možná se ptáte, jak SqlDataAdapter aktualizuje databázi. K vygenerování SQL dotazu používá instanci třídy SqlCommandBuilder, resp. OleDbCommandBuilder. Tento objekt je schopen automaticky generovat SQL dotazy, pokud je nastavena vlastnost SelectCommand objektu DataAdapter.
SqlDataAdapter adapter = new SqlDataAdapter("select * from zamestnanci",
"server=localhost;database=mojeDatabaze;uid=sa;pwd=");
Vlastnost SelectCommand je zde nainicializována konstruktorem.
CommandBuilder se zaregistruje na odchytávání události RowUpdating, kdykoliv je její vlastnost DataAdapter nastavena. V předchozím příkladě to činí konstruktor třídy CommandBuilder.
Událost RowUpdating je vyvolána na začátku běhu metody Update. Pokud se v tuto chvíli zjistí, že vlastnosti InsertCommand, UpdateCommand a DeleteCommand jsou natavené na null. Objekt CommandBuilder nainicializuje tyto vlastnosti vygenerováním příslušných SQL dotazů INSERT,UPDATE nebo DELETE podle vlastnosti SelectCommand.
SelectCommand musí vracet alespoň jeden primární klíč nebo unikátní sloupec. Pokud není nic vráceno je vyvolána výjimka InvalidOperation.
Výjimky se rovněž dočkáte při volání metody DataAdapter.Update pokud nejsou vlastnosti InsertCommand, UpdateCommand nebo DeleteCommand nainicializované a neexistuje SqlCommandBuilder. Samozřejmě můžete tyto vlastnosti nainicializovat samy a vyhnout se tak využití automaticky generovaných SQL příkazů. Při velkém množství aktualizací je takto možné zlepšit výkonnost aplikace.
DataView
Představte si, že jste si naplnili DataSet daty z databáze a nyní ho máte uložený v v mezipaměti, abyste omezili dotazování databáze. Chcete však jednou data zobrazit setřízena podle jednoho klíče, jindy podle nějakého jiného, někdy odfiltrovat nějaké data. V tomto případě sáhnete po třídě DataView, která reprezentuje pohledy ADO.NET. Ty umožňují řazení a filtrování dat.
SqlDataAdapter adapter = new SqlDataAdapter(
"select * from zamestnanci",
"server=localhost;database=mojeDatabaze;uid=sa;pwd=");
DataSetds= new DataSet();
adapter.Fill(ds,"zamestnanci");
DataView pohled = new DataView(ds.Tables["zamestnanci"]);
pohled.Sort = "jmeno";
pohled.RowFilter = "plat > 20000";
DataGrid.DataSource = pohled;
DataGrid.DataBind();
Tento příklad ukazuje řazení. To se provede podle výrazu nastaveného ve vlastnosti Sort objektu pohled. Dále je ve vlastnosti RowFilter nastaven filtrovací řetězec, projdou pouze řádky, které toto kritérium splňují. V tomto příkladě se data setřídí podle sloupce jmeno a budou prezentovány pouze zaměstnanci, kteří mají plat větší než 20000.
Další důležitá vlastnost je RowStateFilter, která se používá k filtrování podle stavu řádků. Tedy podle toho, které byly přidány, smazány či upraveny.
pohled.RowStateFilter = DataViewRowState.Deleted;
Závěr
Tak a máme tu závěr našeho krátkého seriálu o ADO.NET. Samozřejmě se ním nepokrylo celé ADO.NET, na to jsou však k dispozici různé tučné knížky, avšak si myslím, že s těmito základními informacemi a dokumentací SDK pro .NET Framework, případně internetem je již člověk schopný s ADO.NET celkem úspěšně pracovat, což byl i cíl tohoto seriálu.