Zastosowanie Zaawansowanych Technik Obsługi Danych

background image

Zastosowanie
zaawansowanych technik
obsługi danych

Bardzo szybko poznawałeś różne metody dostępu do danych. Teraz, kiedy już opanowałeś
podstawy, nadszedł czas aby przejść na kolejny, bardziej zaawansowany poziom. W tym rozdziale
skoncentrujemy się na technikach bardziej zaawansowanych w porównaniu z tymi,
przedstawionymi w poprzednich częściach niniejszej książki. Poznasz w nim nowe bazy danych
oraz nowe metody operowania na danych XML, które umożliwią Ci tworzenie profesjonalnych
aplikacji internetowych.

W pierwszej kolejności przyjrzymy się metodom pobierania informacji przy użyciu parametrów i
procedur zachowanych. Parametry pozwalają na tworzenie zapytań w sposób bardziej efektywny.
Procedury zachowane są natomiast przygotowywanymi wcześniej poleceniami SQL, których
wykorzystanie przynosi wiele korzyści, do których należy zaliczyć zwiększenie szybkości
działania aplikacji oraz poprawienie jej przejrzystości. Dowiesz się także, w jaki sposób, poprzez
wykorzystanie transakcji, można zapewnić, że polecenia SQL będą wykonywane poprawnie.

W drugiej części tego rozdziału znajdziesz dodatkowe informacje na temat języka XML. Poznasz
klasę

XmlNavigator

, której można używać podobnie jak klasy

XmlDocument

. Wykorzystując

obiekty tej klasy, można zadawać pytania XPath oraz wykonywać przekształcenia XSL. XPath to
języka zapytań stosowany wraz z językiem XML, natomiast XSL to język pozwalający na
przekształcanie plików XML do postaci wszelkich innych dokumentów strukturalnych, takich jak
na przykład dokumenty HTML. Aby stać się ekspertem w dziedzinie ASP.NET koniecznie należy
poznać wiele różnych sposobów umożliwiających uzyskanie tego samego rezultatu. Po
przeczytaniu tego rozdziału będziesz już znał kilka różnych sposobów pobierania informacji z baz
danych oraz plików XML.

W tym rozdziale omówione zostaną następujące zagadnienia:

Czym są zapytania parametryzowane oraz jak należy je stosować.

Czym są procedury zachowane oraz jak należy je stosować.

Jak wykorzystywać transakcje.

Jakie są inne sposoby odczytywania zawartości dokumentów XML.

Sposoby przeszukiwania plików XML.

Sposoby przekształcania plików XML.

background image

Zaawansowane techniki obsługi baz danych

Jak na razie wszelkie operacje związane z wykorzystaniem baz danych były wykonywane przy
użyciu obiektów

OleDbDataAdapter

,

OleDbCommand

,

DataSet

oraz kilku innych. Dostarczają

one wszelkich możliwości funkcjonalnych potrzebnych przy tworzeniu aplikacji ASP.NET.
Jednak nie poznałeś jeszcze wszystkich możliwości jakie obiekty te dają, w szczególności chodzi
tu o parametry, procedury zachowane oraz transakcje.

Parametry są nowym sposobem tworzenia dynamicznych poleceń SQL. Otóż zamiast tworzyć
pytanie SQL składając je z fragmentów pochodzących z wielu różnych źródeł, można wykorzystać
parametry, które poinformują bazę danych jakie informacje należy zwrócić. Takie rozwiązanie jest
nie tylko prostsze, lecz także bardziej eleganckie. Procedury zachowane są natomiast
przygotowywanymi wcześniej poleceniami SQL, które mogą poprawić efektywność działania
aplikacji. Wykorzystanie procedur zachowanych wraz z parametrami stanowi doskonały sposób
przeszukiwania i pobierania informacji z baz danych. Transakcje pozwalają natomiast na
zapewnienie integralności i poprawności informacji poprzez wykonywanie operacji na bazach
danych zgodnie z paradygmatem „wszystko albo nic”. Oznacza to, że zostaną wprowadzone
wszystkie modyfikacje lub nie zostanie wprowadzona żadna z nich. Poznasz także kilka
najczęstszych sytuacji, w których są wykorzystywane transakcje.

Dzięki tym zaawansowanym technikom obsługi baz danych będziesz w stanie tworzyć aplikacje o
znacznie większych możliwościach, a jednocześnie poprawić efektywność ich działania.

Zapytania sparametryzowane

Wyobraź sobie proces budowy domu. Konieczna jest przy tym szczegółowa znajomość wymiarów
elementów konstrukcyjnych oraz miejsc, w których należy ich użyć. Jednym ze sposobów
realizacji tego zagadnienia byłoby zebranie wszystkich elementów i zapisanie wszystkich
informacji bezpośrednio na nich. Na wszystkich panelach podłogowych, oknach, ościeżnicach,
rurach i wszelkich innych elementach, zostałyby zapisane wymiary oraz docelowe położenie. Taka
metoda mogłaby spełnić swoje zadanie, lecz jednocześnie jest bardzo niedokładna i może stać się
przyczyną wielu problemów. Zamiast niej, można jednak wykorzystać plan — kartkę papieru,
która informuje gdzie mają być umieszczone poszczególne elementy i jak je należy połączyć.

Podobnie rzecz się ma z dostępem do danych. Gdy tworzone jest polecenie SQL, można zebrać
poszczególne jego elementy i połączyć je ze sobą w jeden łańcuch znaków, zapisując jednocześnie
informacje o tym za co odpowiadają jego poszczególne części. Można jednak wykorzystać
bardziej zorganizowaną metodę określenia, gdzie należy umieścić poszczególne informacje. Ta
druga metoda wykorzystuje

parametry

— fragmenty informacji tworzone niezależnie od polecenia

SQL i używane w nim. Bazy danych posługują się parametrami w taki sam sposób, w jaki
budowniczy korzystają z planów.

Parametry wykorzystywane są w raz z obiektami

OleDbCommand

w celu podania dodatkowych

informacji, takich jak dane, które należy zwrócić lub sposób ich zapisania w obiekcie

DataSet

.

Przypomnij sobie informacje dotyczące poleceń SQL podane w rozdziale 10, pt.: „Korzystanie z
baz danych za pomocą obiektów ADO.NET”. Aby dynamicznie stworzyć zapytanie,
niejednokrotnie trzeba pobierać informacje z różnych elementów kontrolnych wykorzystywanych
na stronach ASP.NET. Przykładowo, wyobraź sobie następujące zapytanie:

strSQL = "select * from tblUsers where UserID = 1"

Wartość

UserID

mogłaby pochodzić z pola tekstowego wyświetlonego na stronie. A zatem,

można by stworzyć zapytanie w następujący sposób (zakładając, że

tbId

jest nazwą pola

tekstowego):

strSQL = "select * from tblUsers where UserID = " & tbId.Text

Powyższa metoda spełnia swoje zadanie jeśli chodzi o zapewnienie możliwości dynamicznego
stworzenia zapytania SQL, jednak nie jest „zorganizowana”. Co by się bowiem stało gdyby na
stronie były inne pola tekstowe? Wtedy mogłyby się pojawić problemy z określeniem, które z pól
powinno zawierać jakie informacje; największe problemy mieliby inni programiści próbujący
przeanalizować kod strony.

background image

Nowe określenie

Jednak bardziej efektywną metodą jest użycie parametrów.

Parametr

jest wartością przekazywaną

do, bądź zwracaną przez zapytanie. Wykorzystanie parametrów pozwala na zachowanie
przejrzystości informacji i ułatwia analizę stosowanych zapytań. Zastąpmy zatem poprzednie
zapytanie, zapytaniem sparametryzowanym:

strSQL = "select * from tblUsers where UserID = @ID"

Jak widać dynamicznie tworzona część łańcucha znaków została zastąpiona parametrem
zapytania, oznaczonym przy użyciu symbolu

@

. Zauważ, iż parametr ten stanowi część zapytania

SQL. Teraz, w jakimś miejscu, należy podać wartość tego parametru. Wartości parametrów
określane są przy użyciu kolekcji

Parameters

obiektu

OleDbCommand

(więcej informacji na

jego temat znajdziesz w rozdziale 10). Przykład wykorzystania sparametryzowanych zapytań SQL
przedstawiłem na listingu 12.1.

Listing 12.1.

Określanie wartości parametrów zapytania SQL — fragment kodu

1

dim objCmd as OleDbCommand = new OleDbCommand _

2

("select * from tblUsers where UserID = @ID", Conn)

3

4

dim objParam as OleDbParameter

5

objParam = objCmd.Parameters.Add("@ID", OleDbType.Integer)

6

objParam.Direction = ParameterDirection.Input

7

objParam.Value = tbId.Text

Analiza

W wierszach 1. oraz 2., w normalny sposób jest tworzony obiekt

OleDbCommand

(zakładam przy

tym, że został już utworzony obiekt

OleDbConnection

o nazwie

Conn

). Warto zwrócić uwagę na

wiersz 2., w którym tworzone jest zapytanie sparametryzowane. W wierszu 4. tworzony jest obiekt

OleDbCommand

, który zostanie wykorzystany do przekazania wartości parametru do zapytania

SQL. W wierszu 5. parametr użyty w zapytaniu jest dodawany do obiektu

OleDbCommand

, a

jednocześnie określana jest jego nazwa i typ. Nazwa parametry podana w wywołaniu metody

Add

musi odpowiadać parametrowi użytemu w zapytaniu SQL (w tym przypadku musi ona mieć
postać

@ID

). Typ jest wartością

OleDbType

i reprezentuje typ przekazywanej wartości parametru.

Najczęściej stosowane wartości typów przedstawione zostały w tabeli 12.1.

Tabela 12.1.

Najczęściej stosowane wartości

OleDbType

Typ

Opis

Binary

Strumień bajtów (odpowiada tablicy bajtów)

Boolean

Wartość logiczna

BSTR

Łańcuch znaków (odpowiada wartości typu

String

)

Char

Łańcuch znaków (odpowiada wartości typu

String

)

Currency

Wartość monetarna (odpowiada wartości typu

Decimal

)

Date

Data (odpowiada wartości typu

DateTime

)

Decimal

Wartość typu

Decimal

Double

Wartość typu

Double

Empty

Brak wartości

Error

32-bitowy kod błędu (odpowiada wartości typu

Exception

)

Integer

32-bitowa liczba całkowita (odpowiada wartości typu

Integer

)

LongVarChar

Długi łańcuch znaków (odpowiada wartości typu

String

)

background image

VarChar

Łańcuch znaków (odpowiada wartości typu

String

)

Variant

Specjalny typ danych, który może reprezentować dane dowolnego typu, jeśli
ż

aden typ nie został określony (odpowiada wartości typu

Object

)

W wierszu 6. określany jest rodzaj parametru

1

. W tym przypadku parametr będzie

wykorzystywany jako element zapytania

SELECT

, a zatem jego wartość będzie przekazywana

do

zapytania. Stąd też, właściwości określającej rodzaj zostanie przypisana wartość

Input

. Gdyby

wartość była zwracana i zapisywana w parametrze, to jego rodzaj należałoby określić jako

Output

. Więcej informacji na temat kierunków przekazywania informacji przez parametry podam

w dalszej części rozdziału, poświęconej procedurom zachowanym.

W końcu, w wierszu 7., określana jest wartość parametru; w tym przypadku zostaje jej przypisana
zawartość pola tekstowego

tbId

. Dowolne informacje podane w tym polu tekstowym zostaną

zatem przekazane jako parametr do zapytania

select

. Przeanalizuj teraz pełny kod przykładu,

podany na listingu 12.2.

Listing 12.2.

Wykorzystanie parametrów do pobierania informacji z baz danych

1

<%@ Page Language="VB" %>

2

<%@ Import Namespace="System.Data" %>

3

<%@ Import Namespace="System.Data.OleDb" %>

4

5

<script runat="server">

6

dim Conn as new OleDbConnection("Provider=" & _

7

"Microsoft.Jet.OLEDB.4.0;" & _

8

"Data Source=C:\ASPNET\Data\banking.mdb")

9

10

sub GetData(obj as Object, e as EventArgs)

11

dim objCmd as OleDbCommand = new OleDbCommand _

12

("select * from tblUsers where UserID = @ID", Conn)

13

dim objReader as OleDbDataReader

14

dim objParam as OleDbParameter

15

16

objParam = objCmd.Parameters.Add("@ID", _

17

OleDbType.Integer)

18

objParam.Direction = ParameterDirection.Input

19

objParam.Value = tbId.Text

20

21

try

22

objCmd.Connection.Open()

23

objReader = objCmd.ExecuteReader

24

catch ex as OleDbException

25

Label1.Text = "Bł

ą

d pobierania informacji z bazy danych."

26

end try

27

28

DataGrid1.DataSource = objReader

29

DataGrid1.DataBind()

30

31

objReader.Close

32

objCmd.Connection.Close()

33

end sub

34

</script>

35

36

<html><body>

37

<form runat="server">

38

<asp:Label id="Label1" runat="server" /><br>

39

Podaj ID: <asp:TextBox id="tbID" runat="server"

40

AutoPostBack=True

41

OnTextChanged=GetData /><p>

42

<asp:DataGrid id="DataGrid1" runat="server"

43

BorderColor="black" GridLines="Vertical"

44

cellpadding="4" cellspacing="0" width="100%"

45

Font-Name="Arial" Font-Size="8pt"

46

HeaderStyle-BackColor="#cccc99"

1

Rodzaj parametru nazywany jest także „kierunkiem”, gdyż określa on kierunek w jakim parametr będzie

przekazywał informacje.

background image

47

ItemStyle-BackColor="#ffffff"

48

AlternatingItemStyle-Backcolor="#cccccc"

49

AutoGenerateColumns="true" />

50

</form>

51

</body></html>

Analiza

Kod przedstawiony na powyższym listingu powinien wyglądać znajomo — jest on bowiem bardzo
podobny do przykładów wykorzystania informacji pobieranych z baz danych, przedstawionych w
rozdziale 10. W części przykładu zawierającej kod HTML stworzone zostały trzy elementy
sterujące obsługiwane na serwerze:

DataGrid

(zdefiniowany w wierszach od 42. do 49.),

Label

(zdefiniowany w wierszu 39.) oraz

TextBox

(zdefiniowany w wierszach od 39. do 41.). Gdy

użytkownik wpisze jakąś wartość w polu tekstowym, zostanie zgłoszone zdarzenie

TextChanged

;

w wyniku jego obsługi, w elemencie sterującym

DataGrid

zostaną wyświetlone odpowiednio

przefiltrowane informacje (zwróć uwagę na atrybut

AutoPostBack=True

umieszczony w

wierszu 40.). W wierszu 6. deklarowany jest obiekt

OleDbConnection

, który będzie

wykorzystywany w procedurze

GetData

.

Procedura

GetData

jest wykonywana w celu obsługi zdarzenia

TextChanged

generowanego

przez pole tekstowe i służy do wyświetlenia odpowiednich informacji. Nasze sparametryzowane
zapytanie jest tworzone w wierszach 11. i 12. W wierszach do 16. do 19. tworzony jest parametr,
określany kierunek przekazywania informacji oraz jego wartość (wyznaczana na podstawie
wartości właściwości

Text

pola tekstowego

tbID

). Pozostała część procedury pobiera dane i

wiąże je z elementem sterującym

DataGrid

. Na rysunku 12.1 przedstawione zostały wyniki

wygenerowane przez powyższy przykład, po wpisaniu jakiejś wartości w polu tekstowym.

Rysunek 12.1.

Sparametryzowane zapytanie wykorzystujące zawartość pola tekstowego w celu

określenia informacji jakie należy wyświetlić

W jednym zapytaniu można użyć wielu różnych parametrów. Na przykład:

strSQL = "SELECT * FROM tblUsers WHERE UserID=@ID AND FirstName=@Name"

W parametrze można także umieścić wartość zwracaną przez zapytanie:

strSQL = "SELECT @Phone=Phone FROM tblUsers WHERE UserID=@ID
AND FirstName=@Name"

Parametry zwracające informacje określane są jako

parametry wyjściowe

. W efekcie wykonania

powyższego zapytania (

SELECT Phone FROM tblUsers WHERE UserID=@ID AND

FirstName=@Name

) zwrócona przez nie wartość zostanie zapisana w parametrze

@Phone

. Po

wykonaniu tego zapytania, wartość parametru będzie można pobrać z kolekcji parametrów.

background image

Przedstawiony poniżej fragment kodu tworzy parametr wyjściowy dla ostatniego,
przedstawionego wcześniej zapytania SQL:

dim objParam as OleDbParameter
objParam = objCmd.Parameters.Add("@Phone", OleDbType.BSTR)
objParam.Direction = ParameterDirection.Output

Wartość tego parametru można pobrać po wykonaniu zapytania, przy wykorzystaniu właściwości

Value

:

dim strPhone as string = objParam.Value

Parametry są niezwykle przydatne przy tworzeniu dynamicznych zapytań, jednak ich prawdziwe
możliwości uwidaczniają się dopiero przy zastosowaniu wraz z procedurami zachowanymi.

Procedury zachowane

Procedura zachowana jest zbiorem poleceń (zazwyczaj poleceń SQL połączonych z instrukcjami
zapisanymi w innym języku, charakterystycznym dla używanej bazy danych), które baza danych
jest w stanie wykonać. Jaka jest różnica pomiędzy procedurą zachowaną a zwyczajnymi
poleceniami SQL?

Po pierwsze procedury zachowane są kompilowane. Już wiesz jakie korzyści daje kompilowanie
stron ASP.NET. Bardzo podobne korzyści daje kompilacja procedur zachowanych; dotyczy to
także zwiększenia szybkości ich działania.

Nowe określenie

Gdy baza danych wykonuje procedurę zachowaną, tworzony jest

plan wykonania

, który pozwala

na szybsze pobranie informacji w przypadku ponownego wykonania tej samej procedury. Baza
danych analizuje dane oraz zapytanie i określa najbardziej efektywny sposób pobrania i zwrócenia
informacji. Sposób ten zapisywany jest następnie w planie wykonania. A zatem, korzyści jakie
daje stosowanie procedur zachowanych nie wynikają wyłącznie z faktu iż są one kompilowane —
dodatkową zaletą jest stworzenie i późniejsze wykorzystania planu wykonania.

Wykorzystanie procedur zachowanych pozwala na stworzenie kolejnego poziomu abstrakcji
pomiędzy stronami ASP.NET a danymi. Należy pamiętać, że modularność jest jednym z celów
programowania obiektowego. Dzięki oddzieleniu zapytań SQL od stron ASP.NET można:

pozwolić na wielokrotne stosowanie tych samych zapytań,

ułatwić analizę kodu strony ASP.NET,

zaoszczędzić czas.

Jeśli wykorzystywane polecenie SQL jest bardzo długie, to umieszczenie go w stronie ASP.NET
powoduje dodanie do niej kodu, który wcale nie jest tam potrzebny. Takie zapytanie jedynie
utrudni analizę kodu obsługującego faktyczne możliwości funkcjonalne strony. Co więcej, ze
względu na fakt, iż kod zapytania musi zostać przesłany ze strony ASP.NET na serwer bazy
danych, taki sposób wykonywania zapytań powoduje także niepotrzebne wykorzystanie
przepustowości łączy. I w końcu, wyobraź sobie, że to samo zapytanie SQL jest wykorzystywane
w kilku stronach ASP.NET. Jeśli struktura bazy danych ulegnie jakimkolwiek zmianom i pojawi
się konieczność zmiany zapytania, to niezbędne poprawki trzeba będzie wprowadzić na każdej ze
stron, na których dane zapytanie jest używane. W przypadku wykorzystania procedur
zachowanych zmianę wystarczy wprowadzić w jednym miejscu, a jej skutki obejmą całą aplikację.

Przeniesienie poleceń SQL do procedur zachowanych eliminuje wszystkie powyższe problemy, a
jednocześnie daje kilka innych korzyści. Implementacja nawet bardzo prostych, jednowierszowych
zapytań SQL w formie procedur zachowanych da duże korzyści.

Lecz zakończmy te rozważania teoretyczne i stwórzmy w końcu jakąś procedurę zachowaną!

background image

Tworzenie procedur zachowanych w SQL Serverze 2000

Procedury zachowane są wykorzystywane w wielu różnych systemach baz danych. Na przykład,
wykorzystują je zarówno SQL Server jak Microsoft Access, choć w każdej z tych baz danych są
one tworzone w odmienny sposób. W tej części rozdziału pokażę jak należy tworzyć procedury
zachowane w Microsoft SQL Serverze 2000. W następnej części rozdziału zajmiemy się
Accessem.

Właśnie z tego powodu, w tej części rozdziału użyjemy SQL Servera, pomimo tego, iż w
pozostałych częściach książki wykorzystywany był Microsoft Access. Spróbujmy zatem stworzyć
prostą procedurę zachowaną.

Otwórz Enterprise Managera, tak samo jak robiliśmy to w rozdziale 8., pt.: „Podstawowe
wiadomości na temat tworzenia baz danych”. Rozwiń węzły

Microsoft SQL Server

,

SQL Server

Group

, jak również węzeł z nazwą serwera bazy danych oraz węzeł

Databases

. Następnie otwórz

bazę danych

Banking

stworzoną w rozdziale 8. W tym celu kliknij symbol „+” wyświetlony przy

węźle

Banking

(patrz rysunek 12.2).

SQL Server został wyposażony w dużo wbudowanych procedur zachowanych. Można je przejrzeć
klikając węzeł

Stored Procedures

, a następnie dwukrotnie klikając jedną z nazw wyświetlonych w

prawej części okna. Większość z tych predefiniowanych procedur będzie znacznie bardziej
skomplikowana do procedury którą teraz stworzymy; jednak analizując je będziesz mógł zobaczyć
jak powinny wyglądać Twoje procedury. Kliknij prawym przyciskiem myszy na ikonie procedur
zachowanych i z menu podręcznego wybierz opcje

New Stored Procedure

. Na ekranie pojawi się

nowe okienko dialogowe, przypominające to pokazane na rysunku 12.3.

Wyrażenie

[OWNER].[PROCEDURE NAME]

zastąp nazwą jaką chcesz nadać tworzonej

procedurze, na przykład:

SelectIdFromName

. (W tym przypadku nie musisz zwracać uwagi na

atrybut

OWNER

. Więcej informacji na jego temat znajdziesz w dokumentacji SQL Servera 2000.)

Ponieważ chcemy stworzyć sparametryzowane zapytanie, a zatem bezpośrednio po nazwie
procedury i przed słowem kluczowym

AS

należy zdefiniować używane parametry:

CREATE PROCEDURE SelectIdFromName
@FirstName varchar,
@LastName varchar,
@ID int OUTPUT
AS

Słowo kluczowe

OUTPUT

informuje, że w danym parametrze należy zapisać wartość i zwrócić ją

do programu, który wywołał procedurę. Po słowie kluczowym

AS

można podać treść zapytania

SQL:

SELECT @ID = UserID
FROM tblUsers
WHERE FirstName = @FirstName
AND LastName = @LastName

Powyższe zapytanie pobiera wartość pola

UserID

dla użytkownika o podanym imieniu i nazwisku

(polach

FirstName

i

LastName

) i zapisuje ją w parametrze

@ID

. Później wykorzystamy go jako

parametr wyjściowy w kodzie strony ASP.NET. Ewentualnie można także kliknąć przycisk

Check

syntax

, aby sprawdzić czy kod procedury zachowanej został poprawnie zapisany. SQL Server

sprawdzi kod procedury i poinformuje Cię jeśli znajdzie w nim jakiekolwiek błędy. Aby zapisać
procedurę, kliknij przycisk

OK

. Teraz nazwa naszej procedury zachowanej powinna się pojawić na

liście, wraz z nazwami procedur predefiniowanych.

Tworzenie procedur zachowanych w Accessie 2000

Ponieważ we wcześniejszej części książki używaliśmy Microsoft Accessa, zatem pokażę jak
można tworzyć procedury zachowane także w tej aplikacji. Access umożliwia tworzenie procedur
zachowanych jednak określa je jako „kwerendy”. Otwórz zatem bazę danych

Banking

stworzoną

w rozdziale 8 i kliknij zakładkę

Kwerendy

wyświetloną z lewej strony okna pokazanego na

rysunku 12.4.

background image

Rysunek 12.4.

W Accessie procedury zachowane są określane jako „kwerendy”

Znasz zasady tworzenia poleceń SQL, a zatem nie musisz korzystać z kreatorów. Dwukrotnie
kliknij opcję

Utwórz kwerendę w widoku projektu

. Na ekranie pojawi się okienko dialogowe o

nazwie

Pokazywanie tabeli

, zamknij je klikając przycisk

Zamknij

. Spójrz na pasek narzędzi

Accessa, z jego lewej strony powinieneś zauważyć rozwijaną listę o nazwie

Widok

. Wyświetl jej

zawartość, a następnie wybierz z niej opcję

Widok SQL

, tak jak pokazałem na rysunku 12.5.

background image

Rysunek 12.5.

Przejdź do trybu edycji kodu zapytania SQL klikając rozwijaną listę

Widok

wyświetloną z lewej strony paska narzędzi Accessa

Teraz możesz pisać kod zapytania SQL bezpośrednio w tworzonej kwerendzie:

SELECT UserID FROM tblUsers
WHERE FirstName = @FirstName
AND LastName = @LastName

Wpisz kod zapytania w oknie kwerendy, jak pokazałem na rysunku 12.6, a następnie zamknij okno
klikając przycisk

X

widoczny w jego prawym górnym wierzchołku i kliknij przycisk

Tak

, aby

zapisać kwerendę. Zapisz kwerendę pod nazwą

SelectIDFromName

. Teraz powinieneś ją

zobaczyć na liście wszystkich dostępnych kwerend.

Rysunek 12.6.

Wprowadzanie zapytań w programie Microsoft Access, w widoku SQL

Notatka
Mechanizm obsługi baz danych Accessa nie daje mo

ż

liwo

ś

ci stosowania parametrów

wyj

ś

ciowych w kwerendach. Wła

ś

nie z tego wzgl

ę

du w powy

ż

szej kwerendzie nie znajdziesz

parametru

@ID

. W dalszej cz

ęś

ci rozdziału dowiesz si

ę

jak mo

ż

na omin

ąć

to ograniczenie.

U

ż

ycie procedur zachowanych w stronach ASP.NET

Wykonanie procedury zachowanej z poziomu strony ASP.NET jest proste. W tym celu należy
określić wartość jednej właściwości, której do tej pory nie używaliśmy. Właściwość ta nosi nazwę

CommandType

:

dim objCmd as OleDbCommand = new OleDbCommand _
("SelectIDFromName", Conn)
objCmd.CommandType = CommandType.StoredProcedure

background image

W pierwszym wierszu powyższego fragmentu kodu, w standardowy sposób jest tworzony obiekt

OleDbCommand

. Jednak tworząc go nie podaliśmy kodu polecenia SQL, lecz nazwę utworzonej

przed chwilą procedury zachowanej. W 3. wierszu, przypisując właściwości

CommandType

wartość

StoredProcedure

, informujemy ASP.NET, że zostanie wykorzystana procedura

zachowana. Po uzyskaniu tej informacji ADO.NET odszuka procedurę zachowaną w bazie
danych, wykona ją i zwróci uzyskane informacje wynikowe.

Jednak takie wykonanie naszej przykładowej procedury zachowanej nie dałoby oczekiwanych
rezultatów. Przypomnij sobie, że procedura ta zawierała parametry. Aby zwróciła ona
jakiekolwiek dane, konieczne będzie określenie wartości parametrów

@FirstName

oraz

@LastName

. Można to zrobić na dwa sposoby — bezpośrednio lub przy wykorzystaniu kolekcji

OleDbParameters

. Pierwszy z tych sposobów jest bardzo prosty. Wystarczy zmienić pierwszy

wiersz powyższego fragmentu kodu, w sposób przedstawiony na kolejnym przykładzie (przy czym
wartości są wartościami parametrów jakie należy przekazać):

dim objCmd as OleDbCommand = new OleDbCommand _
("SelectIDFromName wartosc, wartosc", Conn)

Na przykład:

dim objCmd as OleDbCommand = new OleDbCommand _
("SelectIDFromName 'Chris', 'Payne'", Conn)

Metoda ta jest bardzo łatwa, lecz niezbyt efektywna, zwłaszcza jeśli jako parametry
wykorzystywane są wartości pobierane, na przykład, z elementów sterujących formularzy. W
przypadku wykorzystania kolekcji parametrów, wartości parametrów naszej przykładowej
procedury zachowanej można by określić w następujący sposób:

dim objParam as OleDbParameter
objParam = objCmd.Parameters.Add("@FirstName", OleDbType.Char)
objParam.Direction = ParameterDirection.Input
objParam.Value = tbFirst.Text

objParam = objCmd.Parameters.Add("@LastName", OleDbType.Char)
objParam.Direction = ParameterDirection.Input
objParam.Value = tbLast.Text

Ten kod powinien Ci coś przypominać. Dokładnie te same czynności wykonywałeś wcześniej w
tym rozdziale, w części pod tytułem „Zapytania sparametryzowane”. Teraz możesz w standardowy
sposób wypełnić obiekt

DataReader

(wywołując metodę

ExecuteReader

obiektu polecenia) i

związać dane z elementem sterującym wyświetlanym na stronie:

try
objCmd.Connection.Open()
objReader = objCmd.ExecuteReader
catch ex as OleDbException
Label1.Text = "Bł

ą

d pobierania informacji z bazy danych."

end try

DataGrid1.DataSource = objReader
DataGrid1.DataBind()

objReader.Close
objCmd.Connection.Close()

A co się stało z naszym parametrem wyjściowym? W Accessie nie da się pobrać wartości

@ID

jako parametru wyjściowego. Niemniej jednak obiekt polecenia zwrócił wartość jako wynik
wykonania zapytania

SELECT

. W poprzednim fragmencie kodu można uzyskać dostęp do tej

wartości za pośrednictwem obiektu

DataReader

. Na listingu 12.3 został przedstawiony

kompletny przykład utworzony poprzez połączenie wszystkich wcześniejszych fragmentów kodu,
wyniki jego pokazano na rysunku 12.7.

Listing 12.3.

Parametry ułatwiają pobieranie danych

1

<%@ Page Language="VB" %>

2

<%@ Import Namespace="System.Data" %>

3

<%@ Import Namespace="System.Data.OleDb" %>

4

background image

5

<script runat="server">

6

dim Conn as new OleDbConnection("Provider=" & _

7

"Microsoft.Jet.OLEDB.4.0;" & _

8

"Data Source=C:\ASPNET\Data\banking.mdb")

9

10

sub SubmitData(obj as Object, e as EventArgs)

11

dim objCmd as OleDbCommand = new OleDbCommand _

12

("SelectIDFromName", Conn)

13

dim objReader as OleDbDataReader

14

objCmd.CommandType = CommandType.StoredProcedure

15

16

dim objParam as OleDbParameter

17

objParam = objCmd.Parameters.Add("@FirstName", _

18

OleDbType.Char)

19

objParam.Direction = ParameterDirection.Input

20

objParam.Value = tbFirst.Text

21

22

objParam = objCmd.Parameters.Add("@LastName", _

23

OleDbType.Char)

24

objParam.Direction = ParameterDirection.Input

25

objParam.Value = tbLast.Text

26

27

try

28

objCmd.Connection.Open()

29

objReader = objCmd.ExecuteReader

30

catch ex as OleDbException

31

Response.Write("Bł

ą

d pobierania informacji z bazy danych.")

32

end try

33

34

DataGrid1.DataSource = objReader

35

DataGrid1.DataBind()

36

37

objReader.Close

38

objCmd.Connection.Close()

39

end sub

40

</script>

41

42

<html><body>

43

<form runat="server">

44

Podaj imi

ę

:

45

<asp:TextBox id="tbFirst" runat="server" /><br>

46

Podaj nazwisko:

47

<asp:TextBox id="tbLast" runat="server" /><p>

48

49

<asp:Button id="btSubmit" runat="server"

50

text="Wy

ś

lij"

51

OnClick="SubmitData"/><p>

52

53

<asp:DataGrid id="DataGrid1" runat="server"

54

BorderColor="black"

55

GridLines="Vertical"

56

cellpadding="4"

57

cellspacing="0"

58

width="100%"

59

Font-Name="Arial"

60

Font-Size="8pt"

61

HeaderStyle-BackColor="#cccc99"

62

ItemStyle-BackColor="#ffffff"

63

AlternatingItemStyle-Backcolor="#cccccc"

64

AutoGenerateColumns="true" />

65

</form>

66

</body></html>

background image

Rysunek 12.7.

Zwracanie wartości przez sparametryzowane procedury zachowane

Obiekt

DataReader

zawiera jeden wiersz oraz jedną kolumnę, w której znajduje się wartość

zwrócona przez procedurę zachowaną.

Notatka
W przypadku SQL Servera 2000 stosowanie parametrów wyj

ś

ciowych jest ze wszech miar

zalecane; a zatem mo

ż

na si

ę

nimi posłu

ż

y

ć

w powy

ż

szym przykładzie i zrezygnowa

ć

z

wykorzystania obiektu

DataReader

. Wi

ę

cej informacji na ten temat znajdziesz we

wcze

ś

niejszej cz

ęś

ci rozdziału, pt.: „Zapytania sparametryzowane”.

Parametry wejściowe i wyjściowe są niezwykle przydatne przy przekazywaniu danych do i z
procedur zachowanych. Istnieją jednak jeszcze inne typy parametrów — takie jak

InputOutput

lub

ReturnValue

— których jeszcze nie poznałeś. Wszystkie dostępne rodzaje parametrów

zostały przedstawione w tabeli 12.2.

Tabela 12.2.

Rodzaje parametrów (kierunki przekazywania informacji)

Rodzaj

Opis

Input

Reprezentuje wartość przekazywaną do zapytania.

InputOutput

Wartość która może być zarówno przekazana do zapytania jak i zwrócona
przez nie.

Output

Wartość zwracana w wyniku wykonania zapytania.

ReturnValue

Reprezentuje wartość zwracaną przez zapytanie, która jednak nie jest
parametrem.

Przedstawiłem już sposoby wykorzystania parametrów wejściowych (

Input

) oraz wyjściowych

(

Output

). Parametry

InputOutput

są przydatne w sytuacjach, gdy dane przekazane do zapytania

mogą ulec zmianie (na przykład, w przypadku aktualizacji bazy). Prosty przykład takiego
zapytania przedstawiłem na poniższym przykładzie, w którym wartość pola

FirstName

należy

zmodyfikować w zależności od jego wartości:

UPDATE tblUsers SET FirstName = "Christopher"
WHERE FirstName = "Chris"

Zapytanie to można by sparametryzować w następujący sposób:

background image

UPDATE tblUsers SET @FirstName = "Christopher"
WHERE @FirstName = "Chris"

W tym przypadku

@FirstName

jest zarówno parametrem wejściowym jak i wyjściowym, a po

wykonaniu polecenia SQL jego wartość ulegnie zmianie. Parametry

InputOutput

doskonale

nadają się właśnie do takich sytuacji.

Parametry

ReturnValue

są bardzo przydatne w poleceniach SQL, które nie zwracają żadnych

wartości pobranych z kolumn bazy danych. Na przykład, przedstawione poniżej zapytanie zwraca
liczbę całkowitą określającą ilość wierszy tabeli:

SELECT Count(*) FROM tblUsers

Zwracana informacja nie pochodzi z żadnej konkretnej kolumny, a zatem nie jest z nią skojarzona
ż

adna nazwa pola. Wartość ta jest zwracana przez zapytanie bez żadnej nazwy ani parametru.

Dane tego typu wspaniale nadają się do obsługi przy użyciu parametrów

ReturnValue

. Aby

pobrać wartość zwracaną przez powyższe zapytanie, należy posłużyć się następującym
fragmentem kodu:

objParam = objCmd.Parameters.Add("RETURN VALUE", OleDbType.Integer)
objParam.Direction = ParameterDirection.ReturnValue

Procedury zachowane są niezwykle przydatnym narzędziem, które może poprawić efektywność
działania aplikacji ASP.NET. Udostępniają one nowe możliwości interakcji z bazami danych,
pozwalając na stosowanie bardzo złożonych zapytań i użycie bardziej zaawansowanych
elementów sterujących baz danych.

Transakcje

Ile razy wykonywałeś skomplikowane zadanie i w połowie zdawałeś sobie sprawę z tego, że
wszystko jest zrobione źle? Czy nie marzyłeś o tym, aby cofnąć czas i zacząć wszystko od nowa?

Bazy danych są w stanie spełnić to marzenie, a wszystko dzięki

transakcjom

. Transakcja to zbiór

pewnych czynności, z których wszystkie muszą zostać wykonane poprawnie lub nie zostanie
wykonana żadna z nich. Na przykład, wyobraź sobie że stworzyłeś złożoną procedurę zachowaną
składającą się z 50 poleceń SQL. Jeśli by nie było transakcji, to gdyby któreś z tych poleceń —
dajmy na to 50-te — zostało wykonane nieprawidłowo, to realizacja całej procedury zostałaby
przerwana i jedno z poleceń nigdy nie byłoby wykonane. Gdybyś chciał wykonać to polecenie, to
musiałbyś najpierw ponownie wykonać 49 poleceń poprzedzających je.

Istnieje bardzo wiele przypadków, gdy takie przerwanie wykonywania serii poleceń jest wysoce
niepożądane. Rozważmy przykład aplikacji bankowej. Użytkownik chce przelać pewną kwotę
pieniędzy ze swego konta rozliczeniowego, na konto oszczędnościowe. W pierwszej kolejności
należy zatem odjąć podaną kwotę z konta rozliczeniowego (którego stan jest przechowywany w
bazie danych), a następnie dodać ją do konta oszczędnościowego (którego stan także jest
przechowywany w bazie danych). Załóżmy, że pierwszy etap operacji został wykonany
poprawnie. Jednak podczas próby dodania przelewanej sumy na konto oszczędnościowe okazuje
się, iż zostało ono zablokowane i w danej chwili nie można do niego niczego dodać. O rany, no to
mamy problem. Kwoty zapisane w bazie danych są nieprawidłowe gdyż z kąta rozliczeniowego
pieniądze już zostały odjęte.

Transakcje zostały zaprojektowane z myślą o właśnie takich sytuacjach. Jeśli w powyższej
procedurze zostałaby użyta transakcja, to nie musielibyśmy się przejmować jakimikolwiek
problemami jakie mogłyby się wydarzyć w trakcie wykonywania całej operacji. Jeśli cokolwiek by
się stało, można by bez problemów odtworzyć wykonane czynności.

Być może przypominasz sobie metody

AcceptChanges

oraz

RejectChanges

klasy

DataSet

, o

których wspominałem w rozdziale 10. Pozwalają one na wykonywanie czynności
przypominających transakcje, lecz działają wyłącznie na informacjach „odłączonych” (czyli już
pobranych z bazy danych). Transakcje obejmują swym działaniem całą bazę danych
wykorzystując przy tym aktywne połączenie, zakładając oczywiście, że serwer bazy danych w
ogóle jest w stanie obsługiwać transakcje (większość komercyjnych serwerów baz danych
dysponuje tą możliwością).

background image

Trzema podstawowymi operacjami każdej z transakcji są — rozpoczęcie transakcji, jej anulacja
bądź zatwierdzenie. Transakcja zaczyna się w momencie jej rozpoczęcia. Wszystkie kolejne
czynności są wykonywane i zapisywane w specjalnym dzienniku, dzięki czemu baza danych może
je później przejrzeć. Anulacja transakcji powoduje odtworzenie wszelkich modyfikacji jakie
zostały wprowadzone. Baza danych odwołuje się przy tym do dziennika i na jego podstawie jest w
stanie określić jaką postać miały informacje w momencie rozpoczynania transakcji. Zatwierdzenie
transakcji sprawia, że informacje zostają uznane za ostateczne i nie będzie ich już można
odtworzyć. W konsekwencji, zatwierdzenie oznacza usunięcie z dziennika bazy danych informacji
o danej transakcji.

Przyjrzymy się teraz typowemu przykładowi wykorzystania transakcji, przedstawionemu na
listingu 12.4.

Listing 12.4.

Zastosowanie transakcji

1

<%@ Page Language="VB" %>

2

<%@ Import Namespace="System.Data" %>

3

<%@ Import Namespace="System.Data.OleDb" %>

4

5

<script runat="server">

6

'deklarujemy polaczenie'

7

dim Conn as new OleDbConnection("Provider=" & _

8

"Microsoft.Jet.OLEDB.4.0;" & _

9

"Data Source=C:\ASPNET\Data\banking.mdb")

10

11

sub Page_Load(obj as Object, e as EventArgs)

12

dim objTrans as OleDbTransaction

13

dim objCmd as OleDbCommand = new OleDbCommand _

14

("DELET FROM tblUsers WHERE UserID=32", Conn)

15

16

Conn.Open()

17

objTrans = Conn.BeginTransaction()

18

objCmd.Transaction = objTrans

19

20

try

21

objCmd.ExecuteNonQuery

22

23

objCmd.CommandText = "INSERT INTO tblUsers " & _

24

"(FirstName, LastName, Address, City, State, " & _

25

"Zip, Phone) VALUES " & _

26

"('Jose', 'Santiago', '34 Lake Drive', " & _

27

"'Yolktown', 'MA', '02515', '8006579876')"

28

objCmd.ExecuteNonQuery()

29

objTrans.Commit()

30

Label1.Text = "Obie operacje zostały wykonane poprawnie."

31

catch ex as OleDbException

32

objTrans.RollBack()

33

Label1.Text = ex.Message & "<p>" & _

34

"

ś

adna operacja nie została wykonana."

35

finally

36

objCmd.Connection.Close()

37

end try

38

end sub

39

</script>

40

41

<html><body>

42

<form runat="server">

43

<asp:Label id="Label1" runat="server"

44

maintainstate=false/>

45

</form>

46

</body></html>

Analiza

Powyższa strona ASP.NET wykonuje dwa polecenie SQL. Jednak jeśli podczas wykonywania
któregoś z nich pojawi się nieprzewidziany problem, to w bazie danych nie zostaną wprowadzone
ż

adne modyfikacje. Na przykład, jeśli drugie polecenie byłoby zapisane w nieodpowiedni sposób,

to nasza operacja zostałaby przerwana w połowie. Jednak dzięki temu, iż przed wykonaniem
jakichkolwiek czynności rozpoczynamy transakcję (w wierszu 17.), to możemy odtworzyć
wszelkie modyfikacje wprowadzone w bazie w wyniku wykonania pierwszego polecenia.

background image

W wierszu 7., w standardowy sposób, jest tworzony obiekt

OleDbConnection

. W wierszu 12.

jest tworzony obiekt

OleDbTransaction

, a w wierszu 14. określamy pierwsze polecenie SQL

jakie zostanie wykonane. Rozpoczęcie transakcji wymaga otworzonego połączenia z bazą danych,
a zatem, w wierszu 16., otwierane jest połączenie. W wierszu 17. rozpoczynamy transakcję,
wywołując w tym celu metodę

BeginTransaction

.

Należy zwrócić uwagę iż

BeginTransaction

jest metodą klasy

OleDbConnection

. Transakcja

musi bowiem zostać zainicjalizowana przez obiekt połączenia. Ten sposób rozpoczynania
transakcji został opracowany celowo, aby nie można było stosować transakcji w razie korzystania
z serwerów baz danych, które ich nie obsługują. Obiekt połączenia jest w stanie określić czy baza
danych obsługuje transakcje czy nie i uniemożliwić rozpoczęcie transakcji jeśli zajdzie taka
potrzeba. Wszystkie dalsze polecenia (anulowanie transakcji lub jej zatwierdzenie) są
wykonywane przy użyciu obiektu

OleDbTransaction

.

W wierszu 18. wskazujemy obiektowi

OleDbCommand

, który obiekt

OleDbTransaction

będzie

wykorzystywany. Do tego celu służy właściwość

Transaction

. Wewnątrz bloku

try

wykonujemy polecenie SQL

DELET

, a następnie tworzymy i próbujemy wykonać polecenie SQL

INSERT

. Jeśli wszystko pójdzie zgodnie z planem, to będzie można wywołać metodę

Commit

, aby

zaakceptować modyfikacje wprowadzone w bazie danych.

Jeśli jednak coś pójdzie nie tak jak zaplanowaliśmy, to chcemy, aby wszelkie modyfikacje zostały
odtworzone. Blok

try

przechwytuje wyjątek i przekazuje wykonywanie do instrukcji

catch

,

gdzie wywoływana jest metoda

RollBack

i wyświetlany stosowny komunikat. Niezależnie od

tego czy został zgłoszony wyjątek czy nie, wykonywany jest blok

finally

, w którym zamykamy

połączenie z bazą danych.

W rezultacie wykorzystania transakcji zostaną wykonane wszystkie polecenia SQL bądź nie
zostanie wykonane żadne z nich.

Zaawansowane techniki obsługi danych
XML

W poprzednim rozdziale dowiedziałeś się w jaki sposób można wykorzystać język XML do
przedstawienia niemal każdego typu informacji. Poznałeś także metody otwierania, odczytywania
oraz zapisywania dokumentów XML z poziomu stron ASP.NET. Niemniej jednak nie są to
wszystkie możliwości wykorzystania i obsługi danych XML.

W kolejnych częściach tego rozdziału przedstawionych zostanie kilka bardziej zaawansowanych
technik manipulowania danymi XML. Dowiesz się jak można się poruszać po dokumentach XML
przy wykorzystaniu obiektów klasy

XmlNavigator

, który pozwala na wykorzystanie dwóch

technologii przedstawionych w dalszej części rozdziału — zapytań XPath oraz przekształceń XSL.
XPath jest językiem zapytań stosowanych do pobierania informacji z dokumentów XML
(podobnie jak język SQL służy do pobierania informacji z baz danych). Przekształcenia XSL
pozwalają na zapisanie zawartości dokumentu XML w formie dokumentu strukturalnego
dowolnego innego typu, na przykład — strony HTML. Dzięki tym technologiom uzyskasz pełną
kontrolę nad dokumentami XML i ich zawartością.

XPathDocument

Nowe określenie

W poprzednim rozdziale dowiedziałeś się jak można poruszać się po tekstowych dokumentach
XML przy wykorzystaniu obiektów klas

XmlNode

i

XmlDocument

. W przypadku prób uzyskania

dostępu do danych XML, obiekty tych dwóch klas tworzą drzewo węzłów. Oznacza to, że
odczytują one zawartość całego pliku XML i tworzą obiektową, hierarchiczną reprezentację
zapisanych w nim informacji. Najprościej rzecz biorąc, obiekt

XmlDocument

pobiera całą

zawartość pliku XML zanim będzie można uzyskać do niej dostęp. Jednak obiekty klasy

XPathDocument

nie tworzą drzew węzłów. Zamiast tego analizują zawartość dokumentu po

background image

jednym węźle. Obiekty te tworzą obiektową reprezentację węzła gdy zostanie on odczytany. Jeśli
chcesz, możesz je sobie wyobrazić jako dynamiczne obiekty

XmlDocument

.

Klasa

XPathDocument

przypomina nieco klasę

XmlDocument

, lecz została stworzona z myślą o

zapewnieniu jak największej efektywności działania i z tego względu nie dysponuje równie
bogatymi możliwościami. Klasa ta została zoptymalizowana pod kątem wykonywania zapytań
XPath (stąd też pochodzi jej nazwa —

XPathDocument

) i przekształceń XSL. Oba te zagadnienia

— zapytania XPath oraz przekształcenia XSL — zostaną opisane w dalszej części rozdziału.
Najpierw jednak przyjrzyjmy się sposobowi wykorzystania obiektu

XPathDocument

przedstawionemu na listingu 12.5.

Listing 12.5.

Tworzenie dokumentu

XPathDocument

1

<%@Page Language="VB" %>

2

<%@Import Namespace="System.Xml" %>

3

<%@Import Namespace="System.Xml.XPath" %>

4

5

<script runat="server">

6

sub Page_Load(obj as object,e as eventargs)

7

'Tworzymy obiekt XPathDocument'

8

Dim objDocument as New XPathDocument _

9

(Server.MapPath("../rozdzial11/books.xml"))

10

end sub

11

</script>

12

13

<html><body>

14

</body></html>

Analiza

W rzeczywistości kod przedstawiony na powyższym listingu nie zawiera niczego nowego — w
wierszach 8. i 9. jest jedynie tworzony nowy obiekt

XPathDocument

. W rzeczywistości, to jest

wszystko co można zrobić z obiektem klasy

XPathDocument

, nie można go bowiem użyć ani do

poruszania się po zawartości pliku XML ani do jego edycji. Obiekty te zostały stworzone w celu
zapewnienia szybkiego dostępu do zawartości plików XML i przesyłania jej bezpośrednio do
innych obiektów, które ją przetworzą.

Konkretnie rzecz biorąc, z obiektem

XPathDocument

najczęściej będzie wykorzystywany obiekt

XPathNavigator

. Dostarcza on metod służących do poruszania się po zawartości plików XML.

W jego skład wchodzą wyłącznie te metody, które sprawiają, iż jest on efektywnym narzędziem
nawigacyjnym. Przykład wykorzystania obiektów

XPathDocument

oraz

XPathNavigator

przedstawiłem na listingu 12.6.

Listing 12.6.

Poruszanie się po dokumencie XML przy wykorzystaniu obiektu

XPathNavigator

1

<%@Page Language="VB" %>

2

<%@Import Namespace="System.Xml" %>

3

<%@Import Namespace="System.Xml.XPath" %>

4

5

<script runat="server">

6

sub Page_Load(obj as object,e as eventargs)

7

Dim objDocument as New XPathDocument _

8

(Server.MapPath("../rozdzial11/books.xml"))

9

10

Dim objNav as XPathNavigator = objDocument. _

11

CreateNavigator

12

objNav.MoveToRoot()

13

DisplayTree(objNav)

14

end sub

15

16

public sub DisplayTree (objNav as XPathNavigator )

17

if (objNav.HasChildren)

18

objNav.MoveToFirstChild()

19

20

Format(objNav)

21

DisplayTree(objNav)

22

23

objNav.MoveToParent()

24

end if

background image

25

26

while (objNav.MoveToNext())

27

Format (objNav)

28

DisplayTree (objNav)

29

end while

30

end sub

31

32

private sub Format (objNav as XPathNavigator)

33

if Not objNav.HasChildren

34

if (objNav.NodeType = XPathNodeType.Text)

35

lblMessage.Text += "" & objNav.Value & "<br>"

36

end if

37

else

38

lblMessage.Text += "&lt;" & objNav.Name & _

39

"&gt;<br>"

40

41

if objNav.HasAttributes

42

while (objNav.MoveToNextAttribute())

43

lblMessage.Text += "&nbsp;&nbsp;&lt;" & _

44

objNav.Name & "&gt; " & objNav.Value & _

45

"<br>"

46

end while

47

48

objNav.MoveToParent()

49

end if

50

end if

51

end sub

52

</script>

53

54

<html><body>

55

<ASP:Label id="lblMessage" runat="server"/>

56

</body></html>

Znaczna część powyższego kodu przypomina przykłady przedstawione w poprzednim rozdziale,
wykorzystujące obiekty

XmlDocument

oraz

XmlNode

. W wierszach 7. i 8. tworzony jest obiekt

XPathDocument

, dokładnie w taki sam sposób jak na przykładzie przedstawionym na listingu

12.5. W wierszach 10. i 11. wywoływana jest metoda

CreateNavigator

obiektu

XPathDocument

. Metoda ta tworzy obiekt

XPathNavigator

, którego będziemy używali do

poruszania się po dokumencie XML. Metoda

MoveToRoot

wywoływana w wierszu 12. powoduje

przejście na sam początek pliku XML, i w końcu w wierszu 13. wywoływana jest stworzona przez
nas procedura

DisplayTree

.

Procedura

DisplayTree

zdefiniowana w wierszach od 16. do 30, jest procedurą rekurencyjną. W

pierwszej kolejności określa ona czy aktualnie analizowany węzeł ma jakiekolwiek węzły
podrzędne. Jeśli ma, to będziemy chcieli wyświetlić informacje o każdym z nich. Wywołanie
metody

MoveToFirstChild

przesuwa kursor do pierwszego węzła podrzędnego. Za samo

wyświetlenie informacji o węźle na wynikowej stronie WWW odpowiada procedura

Format

,

którą niebawem zostanie opisana. W wierszu 21. ponownie wywoływana jest procedura

DisplayTree

, która powtórzy cały proces dla aktualnie przetwarzanego węzła podrzędnego.

Powyższy proces jest powtarzany dla wszystkich węzłów podrzędnych. Gdy każdy z nich zostanie
już przetworzony, zostaje wywołana metoda

MoveToParent

, która przesunie kursor o jeden

poziom w górę hierarchii dokumentu XML.

Także druga część procedury jest rekurencyjna. Odpowiada ona za przeanalizowanie węzłów
znajdujących się na tym samym poziomie hierarchii dokumentu. Do kolejnego węzła na tym
samym poziomie hierarchii można przejść przy wykorzystaniu metody

MoveNext

. Metoda ta jest

wywoływana cyklicznie, aż do momentu gdy przetworzone zostaną wszystkie węzły; w tym
przypadku metoda zwróci wartość

false

, a wykonywania pętli

while

zostanie zakończone.

Wewnątrz pętli wywoływane są metody

Format

oraz

DisplayTree

. Proces ten jest wykonywany

aż do chwili, gdy wszystkie węzły dokumentu XML zostaną przetworzone.

Teraz przyjrzyjmy się procedurze

Format

, zdefiniowanej w wierszach od 32. do 51. Mam

nadzieję, że procedura ta Cię nie przeraża — przeważająca jej część po prostu generuje
formatujące znaczniki HTML. Instrukcja

if

umieszczona w wierszu 33. określa czy dany węzeł

ma jakiekolwiek węzły podrzędne. Jeśli nie ma, to procedura wyświetli jedynie wartość aktualnie
przetwarzanego węzła. Jeśli jednak bieżący węzeł będzie miał jakieś węzły potomne, to
wyświetlona zostanie jego wartość zapisana w nawiasach kątowych. Kolejna instrukcja

if

,

background image

zapisana w wierszu 41., określa czy przetwarzany węzeł ma jakiekolwiek atrybuty i wyświetla
odpowiedni komunikat, jeśli jakieś atrybut zostaną odnalezione. I w końcu, pętla

while

rozpoczynająca się w wierszu 42. pobiera po kolei wszystkie atrybuty węzła i wyświetla je.
Wyniki wykonania powyższego przykładu przedstawiłem na rysunku 12.8.

Rysunek 12.8.

Wykorzystanie obiektu XPathNavigator do wyświetlania danych XML

XPath

XPath jest specyfikacją języka służącego do pobierania fragmentów plików XML, opracowaną
przez Konsorcjum World Wide Web (w skrócie: W3C). Język ten pozwala na zadawanie pytań
służących do przeszukiwania zawartości plików XML, podobnie jak zapytania SQL służą do
przeszukiwania informacji przechowywanych w bazach danych. Język XPath może być dosyć
złożony, więc w tym rozdziale nawet nie spróbuję opisywać jego składni. Zamiast tego
skoncentruję się na zademonstrowaniu sposobu wykorzystania zapytań XPath do przeszukiwania
dokumentów XML.

Zapytania XPath są łańcuchami znaków składającymi się ze słów kluczowych reprezentujących
fragmenty plików XML. Zapytania te są wykonywane przez metodę

Select

klasy

XPathNavigator

. Zakładają, że chcielibyśmy korzystać z naszego przykładowego pliku

books.xml

, wywołanie tej metody mogłoby przyjąć poniższą, przykładową postać:

objNav.Select("descendant::book/author/last-name")

Powyższe zapytanie zwróci nazwiska wszystkich autorów wszystkich książek opisanych w pliku.
Drugie przykładowe zapytanie XPath zwróci natomiast wyłącznie cenę ostatniej książki:

background image

objNav.Select("//book[last()]/price/text()")

Na listingu 12.7 został przedstawiony przykład prostej strony ASP.NET, która umożliwia podanie
zapytania XPath, a następnie je wykonuje i wyświetla uzyskane wyniki.

Listing 12.7.

Wykorzystanie zapytań XPath do pobierania danych XML

1

<%@Page Language="VB" %>

2

<%@Import Namespace="System.Xml" %>

3

<%@Import Namespace="System.Xml.XPath" %>

4

5

<script runat="server">

6

sub SelectData(obj as object,e as eventargs)

7

Dim objDocument as New XPathDocument _

8

(Server.MapPath("../rozdzial11/books.xml"))

9

10

Dim objNav as XPathNavigator = objDocument.CreateNavigator

11

12

lblMessage.Text = ""

13

try

14

dim objIterator as XPathNodeIterator = _

15

objNav.Select(tbQuery.Text)

16

17

While objIterator.MoveNext()

18

lblMessage.Text += "&lt;" & _

19

objIterator.Current.Name & "&gt; " & _

20

objIterator.Current.Value & "<br>"

21

end while

22

catch ex As Exception

23

lblMessage.Text = ex.Message

24

end try

25

end sub

26

</script>

27

28

<html><body>

29

<form runat="server">

30

<h2>Zapytania XPath</h2>

31

<p>

32

Na przyład:<br>

33

<b><code>//book[last()]/@ISBN/text()</b></code> lub

34

<b><code>descendant::book/author/last-name</b></code><p>

35

36

Podaj zapytanie XPath:

37

<asp:Textbox id="tbQuery" runat=server/>

38

<asp:Button id="btnSubmit" text="Wykonaj zapytanie"

39

runat=server OnClick="SelectData"/><p>

40

<asp:Label id="lblMessage" runat=server/>

41

</form>

42

</body></html>

Analiza

W powyższym przykładzie, wszystkie najważniejsze czynności wykonywane są w procedurze

SelectData

, obsługującej zdarzenia generowane przez element sterujący przycisku zdefiniowany

w wierszach 38. i 39. Kod zapisany w wierszach od 7. do 10. powinien wyglądać znajomo —
odpowiada on za stworzenie obiektów

XPathDocument

oraz

XPathNavigator

. Prawdziwa

zabawa zaczyna się natomiast w wierszu 13. gdzie rozpoczyna się blok

try

. Aby zwrócić

poszukiwane dane XML, wykorzystywana jest metoda

Select

, w której wywołaniu zostaje

podane zapytanie

XPath

wpisane przez użytkownika w polu tekstowym. Metoda ta zwraca obiekt

XmlPathNodeIterator

, który pozwala na łatwe przetworzenie uzyskanych wyników. Zwrócone

wyniki są przetwarzane w pętli

while

, która, dzięki wykorzystaniu metody

MoveNext

, pobiera

kolejno każdy ze zwróconych węzłów. Dla każdego z nich wyświetlana jest nazwa i wartość, przy
czym informacje te są określane za pomocą właściwości

Current.Name

oraz

Current.Value

.

Przykładowe wyniki wykonania powyższego przykładu, przedstawione zostały na rysunku 12.9.

background image

Rysunek 12.9.

Przeszukiwanie danych XML przy wykorzystaniu zapytań XPath

Język XPath stanowi bardzo potężny i doskonały mechanizm służący do pobierania danych XML.
Dzięki niemu, nie będziesz już musiał wykonywać zapytań posługując się obiektami

DataSet

.

Więcej informacji na temat zapytań XPath znajdziesz na witrynie WWW W3C, pod adresem

http://www.w3.org/TR/xpath

.

Przekształcenia XSL

Wszystkie instrukcje XSL są obsługiwane przez procesor przekształceń XSL (określany skrótowo
jako XslT, od angielskich słów: XSL transform procesor). Język XSL służy do tworzenia arkuszy
stylów, które informują XslT o tym, w jaki sposób należy przekształcić dane XML. Arkusze
stylów XSL określają jak XslT ma sformatować dane XML po ich przetworzeniu; podobnie jak
kaskadowe arkusze stylów informują przeglądarkę w jaki sposób ma sformatować poszczególne
elementy strony WWW. Na rysunku 12.10 przedstawiłem proces przekształcania jednego
dokumentu XML na drugi.

Procesor przekształceń XSL pobiera fragmenty pliku XML wykorzystując w tym celu zapytania
XPath, a następnie formatuje je na podstawie arkusza stylów XSL. W ASP.NET przekształcenie
dokumentu XML jest bardzo proste — trzeba tylko podać arkusz stylów XSL. Na listingu 12.8
przedstawiłem arkusz stylów

books.xsl

.

Listing 12.8.

Arkusz stylów XSL

1

<xsl:stylesheet

2

xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

3

version="1.0">

4

<xsl:template match="/">

5

<root>

6

<xsl:apply-templates/>

7

</root>

8

</xsl:template>

9

<xsl:template match="bookstore">

10

<HTML><BODY>

11

<TABLE width="450">

background image

12

<TR>

13

<TD><b>Title</b></TD>

14

<TD><b>Price</b></TD>

15

</TR>

16

<xsl:apply-templates select="book"/>

17

</TABLE>

18

</BODY></HTML>

19

</xsl:template>

20

<xsl:template match="book">

21

<TR>

22

<TD><xsl:value-of select="title"/></TD>

23

<TD><xsl:value-of select="price"/></TD>

24

</TR>

25

</xsl:template>

26

</xsl:stylesheet>

Analiza

Powyższy arkusz stylów przekształca dokument XML na dokument HTML. Znaczniki

xsl:template

określają w jaki sposób należy przekształcać konkretne fragmenty dokumentu

XML. Na przykład, fragment arkusza stylów rozpoczynający się w wierszu 20., określa postać
wszystkich węzłów o nazwie

book

.

W tym przypadku przekształcamy dokument XML do postaci dokumentu HTML, co tłumaczy
obecność znaczników

HTML

,

BODY

, itd. Jednak równie łatwo można by przekształcić go do postaci

innego dokumentu XML — wszystko sprowadza się jedynie do podania odpowiednich
znaczników.

Na listingu 12.9 przedstawiony został przykład strony ASP.NET, która wykorzystuje arkusz
stylów XSL z listingu 12.8, aby przekształcić plik

books.xml

do postaci dokumentu HTML.

Listing 12.9.

Wykorzystanie arkusza stylów XSL oraz procesora przekształceń XSL do

przekształcenia pliku XML na dokument HTML

1

<%@ Page Language="VB" %>

2

<%@ Import Namespace="System.Xml" %>

3

<%@ Import Namespace="System.Xml.XPath" %>

4

<%@ Import Namespace="System.Xml.Xsl" %>

5

6

<script runat="server">

7

sub Page_Load(obj as object, e as eventargs)

8

Dim objDocument as New XPathDocument _

9

(Server.MapPath("../rozdzial11/books.xml"))

10

11

Dim objNav as XPathNavigator = _

12

objDocument.CreateNavigator

13

14

Dim objXslT As XslTransform = New XslTransform()

15

dim objWriter as XmlTextWriter = new XmlTextWriter _

16

(Server.MapPath("output.html"), nothing)

17

18

try

19

objXslT.Load(Server.MapPath("books.xsl"))

20

objXslT.Transform(objNav, nothing, objWriter)

21

objWriter.Close

22

23

lblMessage.Text = "Plik został poprawnie zapisany."

24

catch ex As Exception

25

lblMessage.Text = ex.Message

26

end try

27

end sub

28

</script>

29

30

<html><body>

31

<asp:Label id="lblMessage" runat="server"

32

maintainstate=false/>

33

</body></html>

Analiza

Pierwszą rzeczą na jaką należy zwrócić uwagę jest dodatkowa przestrzeń nazw —

System.Xml.Xsl

— importowana w wierszu 4. W wierszach od 6. do 11. wykonywane są

background image

standardowe czynności — stworzenie obiektów

XPathDocument

oraz

XPathNavigator

. W

wierszu 13. tworzony jest obiekt

XslTransform

, a w wierszu 14. obiekt

XmlTextWriter

, który

posłuży nam do zapisania przekształconego dokumentu XML w pliku o nazwie

output.html

.

Wewnątrz bloku

try

plik XSL jest odczytywany i zapisywany w obiekcie

XslTransform

, który

wykorzysta arkusz stylów jako schemat na podstawie którego zostanie określona postać nowego
dokumentu HTML. Następnie wywoływana jest metoda

Transform

obiektu

XslTransform

,

która przekształci dokument XML zgodnie z arkuszem stylów XSL. Pierwszym argumentem
wywołania tej metody jest zawartość pliku XML, którą należy przekształcić (przekazana jako
obiekt

XPathNavigator

, drugim — dodatkowe parametry jakie należy przekazać do pliku XSL

(w tym przypadku żadne parametry nie są przekazywane), a trzecim — obiekt

XmlTextWriter

,

w którym należy zapisać przekształcone dane XML.

W końcu, w wierszu 21. zamykany jest obiekt pisarza, a w wierszu 23. wyświetlany krótki
komunikat informujący o przekształceniu pliku. Po wykonaniu powyższego przykładu, w tym
samym folderze powinien się pojawić plik

output.html

. Będzie on zawierać informacje pobrane z

oryginalnego pliku XML, przedstawione na rysunku 12.11.

Rysunek 12.11. Wyniki wykonania przekształcenia XSL zapisane w formie dokumentu HTML

Przekształcone dane XML można by także zapisać w obiekcie

XmlReader

i wyświetlić na stronie.

W tym celu zmienić kod zapisany w wierszu 19. w następujący sposób:

objReader = objXslT.Transform(objNav, nothing)

W tym przypadku zmienna

objReader

jest obiektem

XmlReader

. I to wszystko. Listing 12.10

przedstawia pełny kod przykładu wykorzystującego obiekt

XmlReader

zamiast obiektu

XmlTextWriter

.

Listing 12.10.

Wyświetlanie przekształconych danych XML przy wykorzystaniu obiektu

XmlReader

1

<%@ Page Language="VB" %>

2

<%@ Import Namespace="System.Xml" %>

3

<%@ Import Namespace="System.Xml.XPath" %>

4

<%@ Import Namespace="System.Xml.Xsl" %>

5

6

<script runat="server">

7

sub Page_Load(obj as object, e as eventargs)

background image

8

Dim objDocument as New XPathDocument _

9

(Server.MapPath("../rozdzial11/books.xml"))

10

11

Dim objNav as XPathNavigator = _

12

objDocument.CreateNavigator

13

Dim objXSLT As XslTransform = New XslTransform()

14

dim objReader as XmlReader

15

16

try

17

objXSLT.Load(Server.MapPath("books.xsl"))

18

objReader = objXslT.Transform(objNav, nothing)

19

While objReader.Read()

20

Response.Write("<b>" & objReader.Name & "</b> " & _

21

objReader.Value & "<br>")

22

End While

23

24

lblMessage.Text = "Plik został poprawnie zapisany."

25

catch ex As Exception

26

lblMessage.Text = ex.Message

27

end try

28

end sub

29

</script>

30

31

<html><body>

32

<asp:Label id="lblMessage" runat="server"

33

maintainstate=false/>

34

</body></html>

Powyższy przykład różni się od kodu z listingu 12.9 jedynie tym, iż został w nim wykorzystany
obiekt

XmlReader

a nie

XmlTextWriter

. Z tego względu HTML uzyskany w wyniku

przekształcenia nie jest zapisywany w pliku. W wierszach od 19. do 22. znajduje się pętla

while

,

która przy użyciu metody

Read

pobiera po kolei wszystkie elementy danych wynikowych i

wyświetla je.

Obiekt

XmlTransform

dysponuje jedynie dwiema metodami —

Load

oraz

Transform

— a

zatem jego wykorzystanie nie powinno przysparzać większych problemów.

Pamiętasz zapewne, że procesor przekształceń XSL wykorzystuje zapytania XPath. Plik XSL
określa nazwy węzłów, które należy przekształcić. Obiekt

XmlTransform

wykorzystuje zapytania

XPath do pobrania węzłów o określonych nazwach, przy czym Ty jako programista nawet nie
wiesz w jaki sposób cały ten proces jest realizowany. Równie dobrze można by samemu użyć tych
zapytań o pobrania danych, a następnie je sformatować. Jednak po co się męczyć jeśli obiekty

XmlTransform

mogą zrobić to za nas?

Więcej informacji na temat XSL można znaleźć na witrynie W3C, na stronach:

http://www.w3.org/TR/xsl

oraz

http://www.w3.org/TR/xslt

.

To nie jest ASP!

Wiele spośród technik opisanych w tym rozdziale jest także dostępnych we wcześniejszej,
tradycyjnej wersji technologii ASP. Na przykład, sparametryzowane procedury zachowane były
kiedyś niezwykle popularnym sposobem wykonywania zapytań SQL. Także operacje na danych
XML można było wykonywać, choć był do tego potrzebny specjalny, dodatkowy komponent
ASP. ASP.NET udostępnia jednak znacznie prostsze sposoby wykonywania tych wszystkich
czynności, gdyż wszystkie konieczne możliwości funkcjonalne są wbudowane bezpośrednio w
ś

rodowisko .NET i są w pełni obiektowe.

Wielu programistów ASP spotkało się już z omawianymi tu zagadnieniami, a zatem
wykorzystanie ich w środowisku .NET nie powinno przysparzać większych trudności. Zmianie
uległ jedynie sposób implementacji; wciąż można natomiast korzystać z istniejących procedur
zachowanych, arkuszy stylów i zapytań XPath. Jedyne co będziesz musiał zrobić, to korzystać z
nich przy użyciu innych obiektów.


Wyszukiwarka

Podobne podstrony:
13transplot-ORT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
adobe premiere 6 biblia zaawansowane techniki montażu (helion) fake OCYCGOTBVADD5AIZJNVFVB7K5LDHKD3V
18obs-imprprzyj-ORT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
27rafting-ORT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
progrwyklORT-sz, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
Debugowanie NET Zaawansowane techniki diagnostyczne debnet
09kp-atnicza-ORT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
24turystkwalif-wstep-ORT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystyczne
ZASTOSOWANIE OSCYLOSKOPU W TECHNICE POMIAROWEJ
Metody i techniki obsługi ruchu turystycznego
17rentacar-ORT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
03kultobs-kl-ORT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
04umwturystyce-ORT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
2 PODSTAWOWE I ZAAWANSOWANE TECHNIKI WYTWARZANIA
10transpwtur-wstep-0RT, Turystyka i rekreacja wykłady, Metody i techniki obsługi ruchu turystycznego
TRENING-ZASTOSOWANIE UMIEJĘTNOŚCI TECHNICZNYCH, Tenis ziemny
zaawansowane techniki wykrywania komputerów w sieci(1) ISIXZ5CHD67VSSQ5QSRNLPUO44BCJ3U7DF6VYYA
access zaawansowane projektowanie baz danych, SPIS TREŚCI

więcej podobnych podstron