ADO.NET w praktyce


Podstawowym elementem, który "wykonuje" operacje na bazie danych, jest SqlCommand. Jest to pośrednik, dzięki któremu można zarówno wywołać procedurę przechowywaną, jak i np. przekazać tekst polecenia SQL na serwer. To zachowanie determinuje właściwość CommandType (może być równa odpowiednio CommandType.StoredProcedure albo CommandType.Text (jest to wartość domyślna). SqlCommand jest tym elementem, który definiuje, w jaki sposób DataAdapter wykonuje aktualizacje (oraz jak pobiera rekordy wypełniając DataSet).

Wiele metod klasy SqlCommand dostępnych jest także na platformie .NET Compact Framework.

Wiele metod klasy SqlCommand dostępnych jest także na platformie .NET Compact Framework.

Właściwość CommandTimeout określa czas oczekiwania klienta na zwrócenie wyniku przez serwer. Domyślnie wynosi 30 s. Uwaga! Ta wartość nie ma nic wspólnego z ConnectionTimeout w SqlConnection - ta właściwość określa czas oczekiwania na otworzenie połączenia. CommandText określa postać polecenia wysyłanego do SQL Server - może to być albo konkretna instrukcja SQL, albo nazwa procedury przechowywanej.

Aby uruchomić SqlCommand, można użyć jednej z poniższych metod:

ExecuteNonQuery - wykonuje polecenie, ale nie zwraca żadnych wyników. Używane jest to np. do wydania polecenia dopisania nowego elementu, skasowania czegoś itp.

ExecuteScalar - wykonuje polecenie i zwraca pierwszą wartość generowaną przez to polecenie.

ExecuteReader - zwraca SqlDataReader - jednokierunkowy kursor do odczytu pozwalający na poruszanie się po zbiorze wyników.

ExecuteXmlReader - zwraca XmlReader (czyli strukturę pozwalającą na pracę z dokumentem XML). Jeżeli CommandText byłoby równe na przykład "SELECT * FROM Customer FOR XML AUTO" (korzystamy tu z możliwości SQL 2005 do transformacji zbioru wierszy do postaci XML), to wtedy XmlReader mógłby poruszać się po zwróconym przez SQL Server dokumencie XML.

XML i .NET

W .NET dostępnych jest bardzo dużo mechanizmów pozwalających na pracę z dokumentami XML. Jeżeli mamy schemat, to najwygodniej jest wygenerować do danego schematu DataSet. Potem możemy pracować z dokumentem, używając konkretnych nazw pól itp. Można też wykorzystać XmlDataDocument.

Inny sposób pozwala pracować z tzw. strukturą DOM - Document Object Model XmlDocument. Wczytuje on cały dokument XML, a następnie tworzy odpowiednią hierarchię składników. Można także wybierać poszczególne węzły, dodawać nowe, tworzyć atrybuty itp. Załóżmy, że mamy taki dokument XML:

<?xml version="1.0" encoding="utf-8" ?>

<root>

<item a1="param1">aaa</item>

<item a2="param1">

<subitem>Q3</subitem>

</item>

</root>

Aby go wczytać, można użyć metody Load z XmlDocument:

XmlDocument doc = new XmlDocument();

doc.Load(@"..\..\xmlfile1.xml");

Jeżeli chcemy być informowani o tym, że jakiś element w środku wczytanego dokumentu uległ zmianie, można ustawić odpowiednią procedurę obsługi zdarzeń (tu reaguje na zmianę wartości w węźle):

doc.NodeChanging += new XmlNodeChangedEventHandler(doc_NodeChanging);

Używając XPath, możemy wybrać elementy z dokumentu (niestety w .NET 2.0 nie jest dostępne XQuery, ale można go użyć w kodzie TSQL):

XmlNodeList nl=doc.SelectNodes(@"/root/item");

Console.WriteLine("Elementów: " + nl.Count.ToString());

W tym wypadku wybieramy 2 elementy item. Można też wybrać jeden węzeł (ten element item, który ma atrybut a1 równy param1):

XmlNode n = doc.SelectSingleNode(@"/root/item[@a1='param1']");

Console.WriteLine(n.InnerXml);

po czym stworzyć nowy element o nazwie Test i dopisać go do danego węzła:

XmlElement el = doc.CreateElement("TEST");

el.InnerText="Value";

n.AppendChild(el);

Console.WriteLine(n.InnerXml);

Jeżeli mamy ustalone wyrażenia XPath, według których wielokrotnie coś wyszukujemy, może się przydać klasa XPathNavigator, która pozwala "skompilować" poszukiwane wyrażenie (generowane jest XPathExpression), co potem przyspiesza proces wyboru wartości z podobnych dokumentów XML.

Jednak XmlDocument nie nadaje się, gdy pracujemy z olbrzymimi dokumentami, które po prostu musimy parsować, wybierając potrzebne informacje. Służą do tego klasy dziedziczone z XmlReader - dokładniej: XmlNodeReader (analizuje kolejne węzły - XmlNode), XmlTextReader, XmlValidatingReader (analizuje kolejne węzły i dodatkowo sprawdza zgodność ze schematem).

Jednak w .NET 2.0 lepiej jest używać składni XmlReader.Create (gdzie przy użyciu parametrów określamy, jakiego typu "reader" zostanie utworzony). XmlReaderSettings pozwala podać, jakie ma być zachowanie obiektu, gdy napotka komentarz, czy ma być używane DTD czy W3C Schema itp. Wtedy można przeanalizować dokument np. w taki sposób:

XmlReader xr = XmlReader.Create(@"..\..\xmlfile1.xml");

xr.MoveToContent();

xr.ReadStartElement("root");

while (xr.Read()) {

Console.WriteLine(xr.Value);

}

Proszę zauważyć, że tu tylko poruszamy się po dokumencie XML, nie wczytujemy go w całości do pamięci (jak ma to miejsce przy użyciu DataSet, XmlDocument czy nawet XpathNavigator).