Základním objektem pro práci s databázemi v .NET Frameworku je DataSet. Je to třída, kterou najdeme ve jmenném prostoru System.Data a která může uchávat tabulky (objekty DataTable) a vztahy mezi nimi (objekty DataRelations).
DataTable je objekt reprezentující tabulku. Obsahuje kolekce Columns (sloupce, reprezentuje je objekt DataColumn) a Rows (řádky neboli záznamy, reprezentovány objektem DataRow), přes které můžeme přistupovat k datům. Jak? Objekt DataRow má vlastnost Item, která může jako parametr přijmout sloupec dané tabulky. Takže pokud budeme chtít vypsat takovou tabulku do stránky, můžeme použít třeba následující postup:
Response.Write("<table>") Response.Write("<tr>") For Each DataColumn c In tabulka.Columns Response.Write("<td><b>" + c.ColumnName) Next c For Each DataRow r In tabulka.Rows Response.Write("<tr>") For Each DataColumn c In tabulka.Columns Response.Write("<td>" + r(c).ToString()) Next c Next r Response.Write("</table>")
Je to o mnoho elegantnější práce s daty než v případě objektu SqlDataReader, nemyslíte? Aby jsme však měli s čím pracovat, musíme objekt DataSet naplnit daty z databáze. K tomu poslouží objekt SqlDataAdapter - tomu můžeme předat SQL dotaz a pak zavolat jeho metodu Fill, která navrácená data převede do DataSetu.
Dim conn As SqlConnection(connString) Dim adap As SqlDataAdapter("SELECT * FROM tabulka WHERE autor = 'xyz'", conn) Dim ds As DataSet = new DataSet() adap.Fill(ds, "tabulka")
Nyní máme DataSet plný dat z tabulky tabulka. Můžeme procházet jednotlivé řádky a libovolně s nimi pracovat. Například přidání nového řádku se provádí voláním metody Add objektu DataRowCollection, což je obsah DataTable.Rows. Jako parametr můžeme zadat pole objektů nebo přímo DataRow (ten můžeme vytvořit pomocí metody NewRow objektu DataTable).
Dim řádek As DataRow = tabulka.NewRow() řádek("ID") = 15 řádek("Jmeno") = "Lukas" řádek("Prijmeni") = "Lansky" tabulka.Rows.Add(řádek)
Odstranit řádek je možno pomocí metody Remove:
tabulka.Rows(1).Remove()
Editovat libovolný záznam je snadné:
tabulka.Rows(1)("Jmeno") = "Ondrej"
Užitečná je možnost změny provedené v této struktuře reflektovat zpět do databáze.
Každý řádek každé tabulky v DataSetu má vlastnost RowChanged, která oznamuje, jestli se řádek změnil od načtení z databáze. RowChanged může nabývat hodnot Unchanged (nezměněn), New (nový), Deleted (vymazaný), Modified (vymazaný). Pak má DataRow metodu AcceptChanges, která zaktualizuje databázi a uvede její obsah na pravou míru s obsahem námi změněného DataRow. Tuto metodu má i DataTable a DataSet - v tomto případě je aktualizována celá tabulka / DataSet.
Po zavolání AcceptChanges se vlastnosti RowChanged dotčených záznamů změní na Unchanged - protože oproti databázi je hodnota nezměněná.
Veškerou další práci s databází můžeme tedy omezit na práci s DataSetem a jeho aktualizace s touto databází. ASP.NET nám ale nabízí další zajímavé možnosti co se týče zobrazování těchto dat uživateli.
Minulý díl jsme zakončili výpisem zdrojového kódu, který je v technologiích ASP a PHP stále běžný. Data jsou uložena v objektu a my nad ním iterujeme a postupně je vypisujeme. Existují však elegantnější metody, kterými můžeme zabezpečit výstup z databáze uživateli.
Technologie svázání dat (Data Binding) nám v ASP.NET umožňuje vypisovat snadno informace do stránky. Nejjednodušší metoda svázání vypadá takto:
<script runat="server"> Dim jmeno = "Ondřej" Sub Page_Load() Page.DataBind() End Sub </script> Uživatel se jmenuje <%# jmeno %>
Zřejmě jste pochopili, že na místo toho divně ohraničeného identifikátoru jmeno se doplní text "Ondřej". Způsobila to metoda objektu Page (který překvapivě reprezentuje vlastní stránku) DataBind. Tento případ ovšem neukazuje technologii v plné síle, neboť by stačilo nahradit uvození "<%#" za "<%=".
Ukažme si poněkud sofistikovanější využití:
<script runat="server"> Dim jmeno As String = "Ondřej" Dim moznaJmena() As String = {"Tomáš", "Josef", "Matěj", "Jakub", "Ondřej"} Sub Page_Load() Page.DataBind() End Sub </script> Uživatel se jmenuje <%# jmeno %>.<br> <form runat="server"> Nebo ne? <asp:ListBox DataSource="<%# moznaJmena %>" runat="server"> </form>
Důležitější než přímé vkládání obsahu proměnné do stránky je možnost svázat data z databáze se serverovým ovládacím prvkem. Ten takto dostane do ruky příslušný datový zdroj - a je zřejmé, že to může být třeba i DataSet. Nabízí to bohatě možnosti...
Představme si například prvek, který převezme zdroj dat, projde jeho prvky, zobrazí je ve formě tabulky a třeba nabídne stránkování bez práce programátora webové aplikace. Beze sporu to možné je - a prvky .NETu pro práci těchto možností plně využívají.
Jako první si ukážeme prvek Repeater. Je to velmi jednoduchá metoda pro zobrazení dat podle definované šablony. Neumí stránkování ani editaci dat, přesto práci zjednodušuje.
Setkáváme se s tímto typem serverového ovládacího prvku poprvé. Sám o sobě nemá žádný význam, musíme mu nejdříve nadefinovat, co za nás má zobrazit. Takže například má dceřinný prvek ItemTemplate - v něm definujeme způsob zobrazení jedné položky v DataTable (pro každý DataRow bude tento kód zobrazen). Je zřejmé, že bude povinný. Podobný je prvek AlternatingItemTemplate, který se ale zobrazuje pro každý druhý záznam (určen je pokud chcete například tvořit tabulku a každý druhý řádek obarvit různou barvou pro lepší vedení oka na široké stránce). Je zřejmě nepovinný. V SeparatorTemplate defunujeme, co se má zobrazit mezi jednotlivými položkami. V HeaderTemplate co se zobrazí před prvním záznamem, podobně FooterTemplate za koncem.
A ještě jednu věc je třeba vědět před pročtením příkladu - vlastní DataBinding se v tomto případě zapíše poněkud rozdílně od původního způsobu. Za prvé musíme intanci objektu Repeater "předhodit" do jeho vlastnosti DataSource zdroj dat pro svázání. Tato vlastnost je typu object a akceptuje objekty, jejichž třídy mají implmentované rozhrnaí IEnumerable, což v praxi znamená, že do ní můžeme vložit datovou tabulku, ale třeba i pole nebo datový řádek. Za druhé si musíme uvědomit, s čím budeme vázat jednotlivé bloky <%# %>. Musíme se zde odvolávat na blok ve kterém se nacházíme (Container) a jeho vlastnost DataItem, která reprezentuje právě procházený řádek dat. Tak tedy:
<script runat="server"> Sub Page_Load() Dim conn As SqlConnection(connString) Dim adap As SqlDataAdapter("SELECT * FROM autor", conn) Dim ds As DataSet = new DataSet() adap.Fill(ds, "autor") rep.DataSource = ds.Tables("autor") DataBind() End Sub </script> <asp:Repeater id="rep" runat="server"> <HeaderTemplate> <table> <tr><td><b>Jméno autora<td><b>E-mail </HeaderTemplate> <ItemTemplate> <tr style="background-color: white;"><td><%# Container.DataItem("jmeno") %> <td><%# Container.DataItem("mail") %> </ItemTemplate> <AlternatingItemTemplate> <tr style="background-color: #DDDDDD;"><td><%# Container.DataItem("jmeno") %> <td><%# Container.DataItem("mail") %> </AlternatingItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:Repeater>
Výstup bude vypadat třeba takto:
Lukáš Lánský | lansky@czech-ware.net |
Jakub Kaplan | cskjr148487@seznam.cz |
Tomáš Srb | 148487cskjr@centrum.cz |
Matěj Štěpánek | csk148487jr@atlas.cz |
Tento přístup vám možná přijde jako poněkud těžkopádný, ve složitějších aplikacích má však svůj půvab a opodstatnění. Mimochodem, podíváte-li se do dokumentace .NET Frameworku a ve jmenném prostrou System.Web.UI.WebControls najdete Repeater, zjistíte, že ItemTemplate a ostatní tyto prvky jsou vlastně vlastnosti Repeateru. V nějaké z příštích lekcí si vysvětlíme, jak vytvářet podobné složité ovládací prvky - to je velmi pěkná demonstrace síly .NETu.
DataList především zavádí dvě nové šablony - SelectedItemTemplate pro zobrazení položky vybrané uživatelem a EditItemTemplate pro položku jež má být uživatelem změněna. To je jeho hlavní výhoda oproti Repeateru, přestože jsou si tyto dva prvky velmi podobné.
Jak předáme ovládacímu prvku zprávu, že chceme tuto řádku zobrazit? Vcelku jednoduše - existuje serverový ovládací prvek LinkButton, který se na klientovi tváří jako klasický odkaz, může však na straně serveru vykonávat speciální funkce určené atributem Command. Zapíšeme-li do něj "Select", DataList tento příkaz "odchytne" a pošle klientovi konkrétní záznam v rozbaleném tvaru. Podobně fungují příkazy "Cancel" (zruší rozbalení položky), "Update" (zobrazí šablonu EditItemTemplate), "Delete" (odstraní danou položku).
Zase tak automatické tyto změny být nemohou, programátor musí dostat možnost, jak reagovat na příslušné události. Proto má DataList parametry, do kterých můžeme vložit názvy obslužných metod, které budou vyvolány po uživatelově akci.
Další zajímavou vlastností je fakt, že už se nemusíme starat o tabulkovou reprezentaci. DataList sám obsahuje vlastnosti, které nastaví výstup do stránky bez dlouhého psaní. Jsou to vlastnosti RepeatLayout, která umožňuje hodnoty Table (klasická tabulka) a Flow (beztabulkové uspořádání) a RepeatDirection, která má hodnoty se zřejmými významy Horizontal a Vertical.
Opět příklad:
<script runat="server"> Sub Page_Load() Dim conn As SqlConnection(connString) Dim adap As SqlDataAdapter("SELECT * FROM autor ORDER BY id", conn) Dim ds As DataSet = new DataSet() adap.Fill(ds, "autor") datl.DataSource = ds.Tables("autor") DataBind() End Sub </script> <asp:DataList id="datl" runat="server" RepeatDirection="Vertical" RepeatLayout="Table" > <ItemTemplate> <asp:LinkButton id="čudlík1" runat="server" Text="<%# Container.DataItem("jmeno") %>" CommandName="Edit" /> </ItemTemplate> <SelectedItemTemplate> <%# Container.DataItem("jmeno") %>: <%# Container.DataItem("mail") %>
</SelectedItemTemplate> </asp:Repeater>
Automaticky se vygeneruje seznam autorů, po kliknutí na nějaké jméno se zobrazí mailová adresa dotyčného autora.
Na příští díl si necháme práci s upravováním položek v DataListu. Představíme si také nejkomplexnější serverový ovládací prvek pro práci s daty, DataGridem a prozkoumáme další taje databázové technologie jako jsou transakce a uložené procedury. Vytvoříme s pomocí databází také inteligentní diskusní fórum, na které si procvičíme všechnu doposud probíranou látku.
Veškeré náměty, dotazy a připomínky pište na adresu lansky@czech-ware.net.