Rozdzia� 27. Klasy baz danych MFC W tym rozdziale: Obiekt CDatabase Obiekt CRecordset Opis klas baz danych MFC Tworzenie prostej narz�dziowej aplikacji wykorzystuj�cej klasy baz danych MFC Nauka dost�pu do parametryzowanego rekordsetu Nauka wywo�ywania parametryzowanej kwerendy Accessa zwracaj�cej dane W rozdziale 26. zapozna�e� si� z ODBC (Open Database Connectivity) i pozna�e� przyczyny, kt�re doprowadzi�y do jego powstania, czyli konieczno�� tworzenia jednolitego interfejsu API do dost�pu do r�nych baz danych. Cho� ODBC z pewno�ci� ma wiele zalet, jednak nie jest pozbawione r�wnie� wad. Jedn� z takich wad jest ilo�� kodu konieczna do przeprowadzenia nawet najprostszej operacji na bazie danych. Za��my, �e Twoja aplikacja ma zrobi� co� tak prostego jak odczytanie wszystkich wierszy ze wskazanej tabeli. Zanim aplikacja korzystaj�ca z ODBC b�dzie mog�a w og�le odczyta� dane z tabeli, musi uzyska� uchwyt �rodowiska, poinformowa� ODBC o wersji ODBC, z kt�rej chce korzysta�, uzyska� uchwyt po��czenia z baz� danych oraz uzyska� uchwyt polecenia. Dorzu� do tego jeszcze kod zwalniaj�cy wszystkie te uchwyty i sprawdzaj�cy poprawno�� wywo�a�, a otrzymasz oko�o stu linii kodu, mimo �e jeszcze nawet nie zacz��e� odczytywa� danych! Z tego powodu Microsoft bardzo szybko zorientowa� si�, co si� dzieje i, poczynaj�c od MFC w wersji 1.5, wprowadzi� zestaw klas MFC reprezentuj�cych funkcje ODBC. Te klasy nosz� og�ln� nazw� klas baz danych i stanowi� temat tego rozdzia�u. Zwr�� uwag�, �e poniewa� klasy baz danych MFC reprezentuj� interfejs ODBC SDK, dobrze by�oby, je�li nie znasz ODBC, aby� zapozna� si� z tre�ci� rozdzia�u 26., przynajmniej po to, aby opanowa� terminologi�, kt�rej b�dziemy u�ywali w tym rozdziale. W tym rozdziale poznasz najpierw cztery g��wne klasy baz danych, CDatabase, CRecordset, CRecordView oraz CDatabaseException. Gdy zapoznasz si� z tymi klasami i ich funkcjami, przejdziemy do omawiania dw�ch przyk�adowych program�w. Pierwszy z nich to w pe�ni funkcjonalna aplikacja narz�dziowa wykorzystuj�ca klasy baz danych MFC. Ta aplikacja ma wszelkie mo�liwo�ci tradycyjnych aplikacji narz�dziowych (tworzenie, odczytywanie, aktualizacja i usuwanie) przeznaczonych do manipulowania tabelami. Drugi program to w rzeczywisto�ci dwa programy demonstracyjne w jednym. W pierwszej cz�ci nauczysz si� u�ywa� parametryzowanych rekordset�w w celu pobierania danych z baz danych Microsoft Access, za� w drugiej cz�ci poznasz spos�b wywo�ywania parametryzowanej kwerendy Accessa zwracaj�cej dane. Klasa CDatabase Obiekt CDatabase reprezentuje po��czenie ze �r�d�em danych. Po skonstruowaniu obiektu CDatabase w wywo�aniu funkcji sk�adowej open ( ) lub openEx ( } nale�y poda� nazw� �r�d�a danych (DSN, data source name). Po��czenie ze �r�d�em danych odpowiadaj�cej DSN-owi nast�puje w momencie wywo�ania kt�rej� z tych funkcji. Obiekt CDatabase jest u�ywany zwykle w po��czeniu z jednym lub kilkoma rekordsetami (kt�re om�wimy za chwil�), lecz mo�e by� wykorzystywany r�wnie� samodzielnie. Przyk�adem u�ycia obiektu CDatabase bez korzystania z obiektu CRecordset mo�e by� wydawanie takich polece� SQL dla �r�d�a danych, kt�re nie powoduj� zwr�cenia �adnych danych. W�a�nie do tego s�u�y funkcja CDatabase: :ExecuteSQL (). Oto przyk�ad pokazuj�cy, jak �atwo jest za pomoc� klasy CDatabase wstawi� rekord do tabeli: try { CDatabase db; if (db.Open("Visual C++ 6 Bibie")) { db.ExecuteSQL("INSERT INTO UserMaster " "VALUES ( 'TestlD' , 'Testowa nazwa u�ytkownika', 0)"); db.Close () ; } } catch(CDBException* pe) { AfxMessageBox (pe->m_strError) ; pe->Delete () ; } Por�wnaj ten fragment kodu z ponad 50 liniami kodu ODBC SDK potrzebnymi do osi�gni�cia tego samego zadania w rozdziale 26.! Klasy baz danych, cho� nie tak wydajne jak bezpo�rednie u�ycie ODBC SDK, z punktu widzenia programisty s� du�o prostsze i szybsze w u�yciu ni� ODBC SDK. Po�wi��my minut� i przyjrzyjmy si� dok�adniej poprzedniemu fragmentowi kodu. Widzimy blok try/catch. try { ... } catch(CDBException* pe) { AfxMessageBox(pe->m_strError); pe->Delete(); } Prawie wszystkie funkcje sk�adowe klasy CDatabase zg�aszaj� w przypadku b��du wyj�tki typu CDBException. Klasa CDBException, wyprowadzona z klasy CEKception, nie wprowadza do niej prawie niczego nowego. W rzeczywisto�ci, poza zmiennymi sk�adowymi odziedziczonymi od klasy bazowej, klasa CDBEKCeption nie definiuje �adnej funkcji sk�adowej. Trzy zmienne sk�adowe s�u�� jedynie poinformowaniu aplikacji o przyczynie zg�oszenia wyj�tku. Oto te trzy zmienne sk�adowe oraz ich zastosowanie przy wyznaczaniu przyczyny wyj�tku: m_nRetCode - przyczyna zg�oszenia wyj�tku w formie kodu zwrotnego ODBC (typu SQLRETURN). m_strError - �a�cuch opisuj�cy b��d, kt�ry spowodowa� zg�oszenie wyj�tku. m_strStateNativeOrigin - �a�cuch opisuj�cy b��d, kt�ry spowodowa� zg�oszenie wyj�tku w formie opisu kodu b��du ODBC. Poniewa� wi�kszo�� funkcji sk�adowych klasy CDatabase mo�e zg�asza� wyj�tki typu CDBEKCeption, dobrze jest w kt�rym� miejscu kodu zastosowa� blok try/catch wychwytuj�cy wyj�tki tej klasy (lub jej klasy bazowej CEKception). Nast�pna linia w poprzednim przyk�adzie konstruuje obiekt CDatabase i otwiera po��czenie ze �r�d�em danych reprezentowanym przez DSN. Jak wida�, nazw� �r�d�a danych jest �Visual C++ 6 Bibie". Ta warto��, w celu zachowania prostoty, zosta�a zaszyta w kodzie, ale zwykle b�dziesz j � podawa� jako typedef, const lub zas�b �a�cucha. CDatabase db; if(db.Open("Yisual C++ 6 Bibie")) ... Konstruktor klasy CDatabase nie robi zbyt wiele. Jak ju� wspominali�my, po��czenie ze �r�d�em danych jest tworzone dopiero w momencie wywo�ania funkcji Open() lub OpenEK (). Tak wi�c skoncentrujmy si� na funkcji Open (). virtual BOOL Open( LPCTSTR IpszDSN, BOOL bEKclusive = FALSE, BOOL bReadOnly = FALSE, LPCTSTR IpszConnect = "ODBC:", BOOL bUseCursorLib = TRUE ); throw( CDBEKCeption, CMemoryEKception ); Jak wida� z tego prototypu, aplikacja mo�e przekaza� funkcji kilka argument�w, ale tak wymagany jest tylko pierwszy z nich. We wcze�niejszym przyk�adzie pierwszy argument by� jedynym i okre�la� nazw� �r�d�a danych. ^Argument bEKclusive okre�la, czy mog� by� otwierane inne po��czenia ze �r�d�em "danych. Ten argument nie by� obs�ugiwany we wcze�niejszych wersjach Visual C++, a dopiero wersja 6.0 obs�uguje warto�� TRUE dla tego argumentu. Argument bReadOnly pozwala aplikacji na wskazanie, czy podczas po��czenia b�dzie mo�liwe aktualizowanie danych w bazie. Domy�ln� warto�ci� tego argumentu jest FALSE, oznaczaj�ca, �e poprzez to po��czenie b�dzie mo�liwe dokonywanie zmian w bazie danych. T� warto�� automatycznie przejmuj� wszystkie obiekty CRecordset tworzone i do��czone do tego obiektu CDatabase. Argument ipszConnect umo�liwia aplikacji wskazanie �a�cucha po��czenia ODBC, u�ywanego, gdy kod MFC klasy CDatabase pr�buje po��czy� si� ze wskazanym �r�d�em danych poprzez ODBC. Je�li ten argument ma by� u�yty, jako argument ipszDSN nale�y przekaza� warto�� NULL. Zalet� korzystania z tego argumentu jest elastyczno��, gdy� w ten spos�b mo�na na przyk�ad przekaza� nazw� u�ytkownika i has�o dost�pu do bazy danych. Format tego argumentu okre�la u�ywany sterownik ODBC. Na koniec, argument bUseCursorLib okre�la, czy ma by� u�yta biblioteka kursora ODBC. Je�li ten argument ma warto�� TRUE (domy�ln�), dla tego po��czenia s� dozwolone jedynie statyczne obrazy danych lub jedynie przewijanie w prz�d. Aby m�c u�y� dynast�w, nale�y w tym argumencie przekaza� warto�� FALSE. Po otwarciu bazy danych nast�pne linie wykonuj � polecenie SQL i zamykaj� baz�: db.ExecuteSQL("INSERT INTO UserMaster " "VALUES('TestlD', 'Testowa nazwa u�ytkownika',0)"); db.Close(); Funkcja CDatabase: :ExecuteSQL () ma bardzo prost� sk�adni�. Aplikacja nie musi robi� niczego wi�cej poza zwyk�ym przekazaniem �a�cucha polecenia SQL, kt�re ma by� wykonane na �r�dle danych. Zwr�� uwag�, �e ta funkcja powinna by� u�ywana tylko wtedy, gdy aplikacja przewiduje, �e w wyniku danego polecenia SQL nie zostan� zwr�cone �adne dane. Jak ju� wspominali�my, alternatywn� metod� otwierania bazy danych jest zastosowanie funkcji sk�adowej CDatabase: :OpenEx (). W rzeczywisto�ci, w�a�nie ta metoda jest zalecana w dokumentacji MFC jako spos�b otwierania po��czenia z baz� danych: virtual BOOL OpenEx(LPCTSTR IpszConnectString, DWORD dwOptions = 0 ) ; throw( CDBException, CMemoryException ); Funkcja CDatabase: : OpenEx () wymaga jedynie dw�ch argument�w: �a�cucha po��czenia oraz warto�ci DWORD reprezentuj�cej opcje po��czenia. Argument IpszConnectString jest u�ywany do przekazywania funkcji �a�cucha po��czenia ODBC, podczas gdy argument dwOptions okre�la spos�b tworzenia tego po��czenia. Jako opcji otwierania bazy mo�na u�y� poni�szych warto�ci, ��cz�c je za pomoc� operatora logicznego LUB: CDatabase::openExclusive CDatabase::openReadOnly CDatabase::useCursorLib CDatabase::noODBCDialog CDatabase::forceODBCDialog Te warto�ci dzia�aj� dok�adnie tak jak w funkcji CDatabase: : Open (). Jedyn� r�nic� jest istnienie znacznik�w CDatabase: : noODBCDialog oraz CDatabase: : f orceODBCDialog. Te znaczniki okre�laj�, czy mened�er sterownik�w ODBC ma wy�wietla� okno dialogowe po��czenia ODBC w momencie pr�by nawi�zania po��czenia. Kolejnym u�ytecznym zestawem funkcji zawartych w klasie CDatabase s� funkcje obs�uguj�ce transakcje. Transakcje daj� aplikacji mo�liwo�� ��czenia zestaw�w wywo�a� funkcji w logiczne grupy. Je�li wywo�anie kt�rejkolwiek z funkcji w grupie logicznej si� nie powiedzie, wszystkie zmiany w bazie danych, dokonane przez poprzednio wywo�ywane funkcje grupy, s� anulowane. Jako przyk�ad, za��my, �e aplikacja ksi�gowa musi przenie�� pewn� kwot� z jednego konta do innego. Co si� stanie, je�li po odj�ciu kwoty z jednego konta nie powiedzie si� pr�ba dodania jej do innego konta? Sp�jno�� bazy danych zostanie oczywi�cie naruszona, gdy� pieni�dze znikn� z jednego konta, ale nie pojawi� si� na...
Morfeusz__