Spis Treści CZĘŚĆ I PROJEKTOWANIE BAZY DANYCH 21 ROZDZIAŁ 1. CO NOWEGO W ACCESSIE 2000 22 Nowy interfejs użytkownika 22 Zmiany w VBE 23 Strony dostępu do danych 24 Podarkusze danych 24 Autokorekta nazw 25 ADO jako domyślny system dostępu do danych 25 Współpraca online 25 Access jako interfejs użytkownika dla SQL Server 26 ROZDZIAŁ 2. PLANOWANIE PROCESU ROZWOJU 27 Określenie wymagań 28 Dlaczego faza wymagań jest tak ważna? 28 Odnalezienie rzeczywistego problemu 28 Śledztwo 28 Diagramy procesu 29 Identyfikacja zakresu projektu 30 Spisywanie wymagań 30 Architektura 31 Planowanie rozwoju 31 Strategia dostarczania 32 Styl 33 Standardy 33 Standardy nazewnictwa 34 Standardy kodowania 34 Konstrukcja 34 Dziel i rządź: działania w fazie Konstrukcja 34 Edycje i kompilacje 35 Szczegółowy projekt 38 Kontrola projektu 39 Tworzenie aplikacji 39 Kontrola aplikacji 39 Testowanie 39 Testowanie modułu 39 Testowanie aplikacji 40 Testowanie instalacji i konfiguracji 40 Odnajdywanie usterek 41 Kontrola wersji 43 ROZDZIAŁ 3. PROJEKT BAZY DANYCH I NORMALIZACJA 45 Relacyjne systemy zarządzania bazami danych (RDBMS) 45 Zasady relacyjne dr Codda 45 Teoria projektowania relacyjnego 47 Korzyści z używania modelu relacyjnego 47 Tabele i niepowtarzalność 48 Klucze obce i domeny 48 Relacje 49 Relacja jeden-do-jednego 49 Relacja jeden-do-wielu 49 Relacja wiele-do-wielu 50 Podarkusze danych 50 Normalizacja danych 51 Pierwsza postać normalna 51 Druga postać normalna 52 Trzecia postać normalna 52 Korzyści z normalizacji 53 Zasady integralności danych 53 ROZDZIAŁ 4. ZAAWANSOWANE KWERENDY 54 Kwerendy w Accesie 2000 54 Tworzenie zaawansowanych kwerend 55 Użycie kwerendy 55 Właściwości kwerendy 56 Siatka QBE 56 Panel tabel 58 Umieszczanie tabeli lub kwerendy w panelu tabel 58 Tworzenie relacji w panelu tabel 58 Siatka kwerendy 61 Umieszczanie pól w siatce kwerendy 62 Określanie kolejności sortowania, wyświetlania rezultatów oraz wybór kryteriów kwerendy 62 Kwerendy podsumowujące 62 Funkcja agregująca Policz 63 Funkcja agregująca Średnia 64 Funkcje agregujące Minimum i Maksimum 64 Funkcje agregujące Pierwszy i Ostatni 65 Funkcje agregujące Odchylenie standardowe i Wariancja 65 Funkcja Wyrażenie 65 Warunek Gdzie 66 Użycie kwerend krzyżowych 67 Użycie kwerend parametrycznych 69 Tworzenie parametrów dla kwerendy w siatce QBE 70 Tworzenie parametrów w kwerendach korzystających z programu 71 Tworzenie kwerend parametrycznych – siatka QBE a program 71 Wykonywanie kwerendy parametrycznej poprzez program 71 Wykonywanie kwerendy poprzez zbiór parametrów 72 Kwerendy przekazujące 72 Tworzenie kwerendy przekazującej 73 Kwerendy definiujące dane 73 Tworzenie nowej tabeli 74 Modyfikowanie tabeli 74 Tworzenie indeksów 75 Usuwanie tabeli 75 Określanie właściwości pól 75 Optymalizowanie kwerend 76 ROZDZIAŁ 5. JET 4.0 – SILNIK BAZ DANYCH MICROSOFT 77 Historia Microsoft Jet 77 Jet 1.0 77 Jet 1.1 77 Jet 2.0 77 Jet 2.5 78 Jet 3.0 78 Jet 3.5 78 Jet 3.51 78 Jet 4.0 78 Przyszłe wersje Microsoft Jet 79 Praktyczne zastosowanie nowych opcji silnika Jet 4.0 79 Wbudowany dostawca baz danych OLE 79 Blokowanie na poziomie rekordu 79 Pełna obsługa Unicode 79 Czym jest Unicode? 79 Obsługa Unicode 1.1 w silniku Jet 4.0 80 Sortowanie kompatybilne z NT 81 Typy danych Jet 81 Ulepszenia opcji Autonumerowanie 82 Przeszukiwalne pola Memo 83 Kontrola połączeń i zamknięcie bierne 83 Nowa składnia SQL 84 Zabezpieczenia 84 Definiowanie widoków i procedur 85 Wywoływanie parametrów 85 Transakcje 85 Tworzenie tabel DDL 86 CZĘŚĆ II DOSTĘP DO DANYCH 88 ROZDZIAŁ 6. WPROWADZENIE DO OBIEKTÓW DANYCH ACTIVEX 89 Historia dostępu do danych 89 Firmowe interfejsy API 89 Open Database Connectivity (ODBC) 89 Microsoft Jet/Obiekty Data Access (DAO) 90 Zdalne obiekty danych (RDO) i ODBCDirect 90 Universal Data Access 90 Obiekty ActiveX Data (ADO) 91 ADO 1.0 91 ADO 1.5 91 ADO 2.0 91 ADO 2.1 91 Model obiektowy ADO 92 Obiekt Connection 93 Otwarcie połączenia w Accessie 2000 93 Wykonywanie wyrażeń SQL w obiekcie Connection 94 Obiekty ADO: Recordset 94 Użycie Recordset z obiektami Command i Parameter 96 Wykonywanie kwerendy funkcjonalnej poprzez obiekt Command 98 Obiekty Field i Property 99 Obiekty ADO: Error 100 Przejście z obiektów DAO do ADO 101 Konwersja z poprzednich wersji Accessa 101 Czy warto przejść na obiekty ADO? 101 Schemat konwersji 101 Kiedy nie dokonywać konwersji? 102 Porównanie modelu obiektowego ADO i DAO 102 ROZDZIAŁ 7. ZAAWANSOWANE ADO 104 Użycie dostawcy OLE DB dla Jet w Accessie 2000 104 CurrentProject.Connection 106 Rola Microsoft Data Links w podłączaniu się do bazy danych 106 Zarządzanie plikami UDL 108 Programowe zarządzanie plikami UDL 108 Uzyskanie poprzez ADO dostępu do danych w bazach nierelacyjnych 110 Lista użytkowników Jet 110 Tworzone zestawy rekordów 110 Kształtowanie danych 111 Zaawansowana obróbka danych przy użyciu ADO 113 Modyfikowanie danych w zestawie rekordów 113 Dodawanie rekordu 114 Trwałe zestawy rekordów 115 Definiowanie danych przy użyciu ADOX 117 Obiekt Catalog 117 Tworzenie bazy danych 117 Tworzenie tabel i pól 118 Tworzenie dołączonej tabeli 118 Ustawianie właściwości pola 119 Tworzenie indeksu 119 Tworzenie relacji w ADOX 120 Tworzenie kwerend w ADOX 121 Tworzenie widoku 121 Tworzenie procedury 122 Modyfikowanie wyrażenia SQL kwerendy 122 CZĘŚĆ III INTERFEJS UŻYTKOWNIKA 124 ROZDZIAŁ 8. PROJEKTOWANIE FORMULARZA 125 Właściwości formularza 125 Zakładka Dane 126 Źródło rekordów 126 Edycja dozwolona 126 Usuwanie dozwolone 126 Dodawanie dozwolone 126 Wprowadzanie danych 126 Filtry dozwolone, Filtr, Uporządkuj według 126 Zakładka Format 126 Widok domyślny 126 Dostępne widoki 127 Paski przewijania 127 Selektory rekordów 127 Przyciski nawigacyjne 127 Styl obramowania 127 Pole menu sterowania 127 Przyciski Min Max 127 Przycisk Zamknij 127 Zakładka Inne 128 Modalny 128 Podręczny 128 Pasek menu, pasek narzędzi 128 Menu podręczne 128 Pasek menu podręcznego 128 Metka 128 Ma moduł 128 Zezwolenie na zmiany projektu 129 Użyteczne właściwości nie znajdujące się na arkuszu właściwości 129 Argumenty otwarcia (OpenArgs) 129 Właściwości użytkownika 129 Zdarzenia 130 Otwarcie formularza 130 Zamknięcie formularza 131 Zmiana rozmiaru formularza 131 Maksymalizowanie formularza 131 Przywrócenie zminimalizowanego formularza 131 Formanty formularza w Accessie 131 Formant Lista rozwijana 131 Użycie zdarzenia Not In List 131 Tworzenie automatycznie rozwijającej się listy rozwijanej 132 Tworzenie własnych list rozwijanych 132 Pobieranie więcej niż jednej wartości z pola listy i listy rozwijanej 133 Pole listy 133 Pole listy wielokrotnego wyboru 133 Ustawienia właściwości 134 Podformularze 134 Dodawanie podformularzy 134 Tworzenie odniesienia dla podformularza 135 Wbudowany formant Karta 135 Grupa opcji 135 Podręczne menu 136 Hiperłącza 136 ROZDZIAŁ 9. ROZBUDOWA FORMULARZY PRZY UŻYCIU FORMANTÓW ACTIVEX 137 Jak korzystać z formantów ActiveX 137 Typy formantów ActiveX 137 Gdzie znaleźć formanty ActiveX? 138 Czy formanty ActiveX są bezpieczne? 138 Czy mogę korzystać z formantów ActiveX i rozpowszechniać je w moich aplikacjach? 138 Użycie formantów ActiveX 139 Instalowanie formantu ActiveX 139 Rejestrowanie formantów ActiveX 139 Dodawanie formantu ActiveX do formularza 139 Ustawianie właściwości formantu ActiveX 140 Pisanie kodu umożliwiającego wykonywanie metod i reagowanie na zdarzenia 141 21 formantów ActiveX 141 Formant Animation 142 Formant Calendar 143 Formant Common Dialog 143 Formant DateTimePicker 144 Formant FlatScrollBar 145 Formant ImageCombo 145 Formant ImageList 146 Formant ListView 147 Formant MAPISession 149 Formant MAPIMessages 149 Formant MonthView 150 Formant ProgressBar 151 Formant RichText 152 Formant Slider 152 Formant StatusBar 153 Formant SysInfo 154 Formant TabStrip 155 Formant Toolbar 155 Formant TreeView 156 Formant UpDown 157 Formant WebBrowser 158 Dystrybucja formantów ActiveX 159 ROZDZIAŁ 10. TWORZENIE RAPORTÓW 160 Czym są raporty? 160 Struktura raportów w Accessie 161 Tworzenie prostych raportów przy użyciu kreatora 161 Dostosowywanie raportów 163 Zmiana źródła rekordów w raporcie 163 Zmiana struktury grupowania w raporcie 164 Umieszczenie grupowania w raporcie 165 Użycie funkcji w raporcie 166 Użycie funkcji obliczeniowych 166 Użycie Funkcji Immediate IF 166 Użycie własnych funkcji w module raportu 167 Użycie własnych funkcji w osobnym module 167 Użycie konkatenacji 168 Praca z podraportami 169 Tworzenie prostego podraportu 170 Tworzenie prostych etykiet adresowych 171 Publikowanie raportu 172 Metody publikowania raportów 172 Użycie wbudowanych metod Accessa do eksportowania raportów 173 Użycie łączy pakietu Office do publikowania raportów 174 Problemy związane z publikacją 174 Użycie poczty elektronicznej do publikowania raportów 174 Modyfikowanie raportu podczas jego działania 174 Filtrowanie i sortowanie 174 Trzymaj grupę razem 175 HasData 175 Zdarzenia raportu (podczas jego działania) 175 Przy otwarciu 175 Przy aktywowaniu, przy dezaktywowaniu 175 Przy braku danych 176 Przy błędzie 176 Przy stronie 176 Przy zamknięciu 176 Właściwość Sekcja 176 Nazwa 176 Wysokość 177 Widoczny 177 Właściwości sekcji związane z procesem projektowania 177 Można powiększać, można zmniejszać 177 Nowy wiersz lub kolumna 177 Powtórz sekcję 178 Właściwości sekcji (podczas działania raportu) 178 Wymuszaj nową stronę 178 Trzymaj razem 178 PrzenieśUkład, NastępnyRekord i DrukujSekcję 178 LiczbaFormatowań 179 LiczbaDrukowań 179 ByłKontynuowany, BędzieKontynuowany 179 Programowe tworzenie raportów 179 Tworzenie źródła rekordów 179 Tworzenie obiektu Raport 180 Tworzenie sekcji 182 Wskazówki 182 Tworzenie grupowania dwutygodniowego 182 Ukryj powtarzające się dane 182 Alfabetyczne grupowanie danych 182 Tworzenie numerowanych list 183 Tworzenie pustych linii co n znaków 183 Zerowanie numeru strony dla nowych grup 184 Rysowanie pionowych linii 184 Przesuwanie numerów parzystych i nieparzystych stron 184 Identyfikacja użytkownika drukującego raport 184 Wyrównanie stron do oprawy 185 Obliczanie podsumowań strony 185 Precyzyjne przesuwanie formantów 185 CZĘŚĆ IV TAJNIKI VBA 187 ROZDZIAŁ 11. TWORZENIE OBIEKTÓW PRZY UŻYCIU MODUŁÓW KLAS 188 Korzyści z używania obiektów 189 Ukrywanie złożoności 189 Użycie technologii Microsoft IntelliSense 189 Organizowanie kodu 190 Dopuszczenie przeglądania obiektów w Object Browser 190 Tworzenie wielu egzemplarzy obiektów 190 Tworzenie kodu łatwego do aktualizacji i utrzymania 190 Ograniczenie dostępu do kodu 190 Tworzenie przenośnego kodu 191 Przegląd obiektów, właściwości i metod 191 Tworzenie klas 191 Wstawianie modułu klasowego 191 Tworzenie właściwości 192 Użycie zmiennych publicznych 192 Użycie procedur właściwości 192 Tworzenie w module zmiennych prywatnych 193 Property Let 193 Property Get 193 Property Set 194 Zmienna publiczna czy procedury właściwości 194 Tworzenie wyliczeniowych typów danych 194 Tworzenie metod 196 Użycie metod 196 Tworzenie zdarzeń 196 Użycie zdarzeń 197 Uruchamianie zdarzeń „Przy inicjacji” i „Przy zakończeniu” 198 Użycie obiektów 198 Tworzenie zmiennej obiektu 198 Przypisywanie zmiennej obiektu do obiektu 198 Użycie obiektu 199 Zwalnianie obiektu 199 Tworzenie wielu egzemplarzy obiektów 199 Przegląd innych obiektów 200 Obiekt TextFile 200 Obiekt Timer 200 Obiekt Sound 201 Obiekt Letter 202 Obiekt Outlook 203 Implementacja obiektu obsługi błędów 204 Użycie obiektów w połączeniu z kolekcjami VBA 204 Tworzenie kolekcji VBA 205 Właściwości i metody kolekcji VBA 205 Dodawanie obiektów do kolekcji 205 Odnoszenie się do określonych obiektów 206 Tworzenie pętli po obiektach kolekcji 206 Usuwanie pojedynczych obiektów 206 Usuwanie wszystkich obiektów 206 Zwalnianie zmiennej obiektu 207 ROZDZIAŁ 12. USUWANIE BŁĘDÓW W APLIKACJACH ACCESSA 208 Usuwanie błędów logicznych 208 Praca z Visual Basic Development Environment (IDE) 209 Project Explorer 209 Okno Code 209 Okno Properties 210 Okno Immediate 210 Okno Locals 210 Okno Watch 210 Object Browser 211 Okno Call Stack 211 Obiekt Debug 211 Debug.Print 211 Debug.Assert 212 Użycie okna Immediate 212 Podglądanie zmiennych 212 Zmiana wartości zmiennych 212 Wyświetlanie wartości funkcji wbudowanych 213 Uruchamianie funkcji własnych 213 Uruchamianie własnych procedur 213 Wskazówki pomocne w korzystaniu z okna Immediate 213 Uruchamianie instrukcji w oknie Immediate 213 Poruszanie się po oknie Immediate 213 Usuwanie kodu w oknie Immediate 213 Użycie programu uruchomieniowego 213 Ustawianie punktów zatrzymania 214 Przechodzenie przez kod 214 Krokowe wykonywanie kodu 214 Wykonywanie procedur 214 Wykonywanie kodu do końca procedury 214 Wykonanie do pozycji kursora 215 Wybór kolejnej instrukcji 215 Kontynuacja wykonywania kodu 215 Ponowne uruchamianie kodu 215 Podglądanie wartości zmiennych 215 Użycie podczas usuwania błędów technologii Microsoft IntelliSense 215 Użycie okna Locals 216 Użycie okna Watch 216 Użycie okna Call Stack 216 Użycie kompilacji warunkowej 217 Pisanie solidnego kodu 217 Deklaruj zmienne w osobnych liniach programu 217 Deklaruj zmienne w jak najwęższym zakresie 218 Używaj określonych typów danych 218 Niszcz zmienne obiektów 218 Używaj słowa kluczowego TypeOf 218 Używaj Me zamiast Screen.ActiveForm i Screen.ActiveControl 218 Używaj narzędzia do obsługi błędów 218 Używaj Option Explicit 218 Numeracja od 0 czy od 1? 218 Natychmiast naprawiaj błędy 218 Używaj komentarzy 218 Używaj znaku kontynuacji wiersza 219 Używaj krótkich procedur 219 Używaj standaryzowanych konwencji nazewnictwa 219 Nigdy nie używaj Stop 219 Nie usuwaj błędów przy użyciu okien komunikatu 219 Testowanie aplikacji 220 Ćwiczenie technik usuwania błędów 220 ROZDZIAŁ 13.  PROFESJONALNA OBSŁUGA BŁĘDÓW 221 Usuwanie błędów składni 221 Usuwanie błędów logicznych 223 Usuwanie błędów wykrytych w trakcie użytkowania 223 Proste narzędzie do obsługi błędów 223 On Error GoTo ErrorHandler 223 ExitHere 223 ErrorHandler 224 Resume ExitHere 224 Przebieg programu z narzędziem do obsługi błędów 224 Obiekt Err 225 Err.Clear 225 Err.Raise 225 Reagowanie na błędy 226 Instrukcje Resume 227 Resume 227 Resume Next 227 Uzyskiwanie dodatkowych informacji o błędzie 227 Zaawansowane narzędzie do obsługi błędów 228 Moduł klasowy Error (Obiekt) 229 Właściwości obiektu cError 229 Metody obiektu cError 230 Przeglądanie obiektu cError w Object Browser 231 Przetwarzanie błędu 231 Doświadczenie użytkownika końcowego 232 Identyfikowanie problemów sprzętowych 234 Sporządzanie raportów o błędach 234 Opcje obiektu cError 235 Odwołania do interfejsu API systemu Windows 236 Błędy w różnych aplikacjach 237 Obsługa błędów w procedurach zagnieżdżonych 237 Zaawansowane zagadnienia związane z błędami 237 Procedury zdarzeń związane z błędami 237 On Error GoTo 0 238 On Error Resume Next 238 Metoda AccessError 238 Inne funkcje związane z błędami 238 Ustawienie opcji wyłapujących błędy 238 ROZDZIAŁ 14. OPTYMALIZACJA APLIKACJI 240 Ulepszanie podstaw: optymalizacja sprzętu i systemu Windows 241 Instalowanie aplikacji w celu uzyskania optymalnej wydajności 242 Optymalizacja silnika bazy danych Jet 242 Bezpieczne modyfikowanie ustawień silnika Jet 246 Narzędzia służące do pomiaru wydajności 247 Spojrzenie za kulisy 248 Optymalizacja bazy danych od podstaw 249 Projektowanie tabel w celu osiągnięcia poprawy wydajności 249 Normalizacja danych w celu osiągnięcia poprawy wydajności 249 Tworzenie indeksów w celu przyspieszenia pracy kwerend 250 Wcześniejsze tworzenie relacji jako sposób na poprawę wydajności 250 Poprawa wydajności kwerend 250 Wybór typu zestawu wyników zapewniającego optymalną wydajność 252 Zwiększenie szybkości kwerend 253 Przyspieszenie funkcjonowania formularzy 255 Zacznijmy od początku 255 Szybsze pobieranie rysunków 255 Podstawowy, szybki formularz 256 Szybsze drukowanie raportów 258 Pisanie szybkiego kodu 258 Użycie pamięci przez kod 259 Praca z modułami 259 Kompilowanie kodu 259 Dekompilacja 259 Tworzenie pliku MDE 260 Użycie Option Explicit 260 Precyzyjne wybieranie rozmiaru zmiennych 260 Oszczędzanie przestrzeni stosu przy użyciu zmiennych typu string 260 Dokładne określanie typu obiektów 260 Umieszczenie kodu we wnętrzu procedury zamiast odwoływania się do innych funkcji 261 Zmiana True i False 261 Użycie Len() zamiast pustego ciągu 261 Użycie True i False zamiast zera 261 Szybkie odwołania do obiektów 261 Użycie szybkich tablic 262 Używaj stałych, gdy jest to tylko możliwe 262 Właściwe użycie zakładek (Bookmarks) 262 Zamykaj i niszcz 263 Używaj SQL zamiast DAO 263 Użycie indeksowania kolekcji 263 Tworzenie szybszych pętli 263 Usuń z kodu IIF() 264 Porządkowanie Select Case 264 Używaj Execute zamiast RunSQL 264 Używaj A2KU_Timer 264 Testuj wydajność transakcji 264 Kontroluj odświeżanie 264 Używaj wczesnego wiązania i zwracaj uwagę na odniesienia ActiveX 265 Przejście do architektury klient-serwer 265 Chleba i igrzysk 265 CZĘŚĆ V ACCESS I ARCHITEKTURA KLIENTSERWER 266 ROZDZIAŁ 15. WPROWADZENIE DO PROJEKTÓW PROGRAMU MICROSOFT ACCESS ORAZ NARZĘDZI WIZUALNYCH 267 Wprowadzenie do projektów programu Microsoft Access 267 Wady i zalety ADP 267 Użycie ADP 268 Tworzenie ADP 268 Nowe okno bazy danych 269 Praca z ADP i istniejącymi bazami danych serwera SQL 270 Praca z tabelami 270 Widoki w serwerze SQL 271 Procedury przechowywane 272 Diagramy bazy danych 272 Formularze, strony, raporty i moduły 273 Zarządzanie serwerem SQL poprzez ADP 273 Składowanie i odtwarzanie 273 Replikacja serwera SQL 274 Bezpieczeństwo 274 Powtórne przyłączenie do bazy serwera SQL 275 Tworzenie projektu opartego na nowej bazie danych 276 Tworzenie tabel 276 Ustawienie właściwości tabeli i indeksów 277 Tworzenie zależności na diagramie bazy danych 277 Tworzenie kaskad poprzez wyzwalacze 278 Tworzenie widoków 278 Tworzenie procedur przechowywanych 279 Tworzenie aplikacji w Accessie 279 Tworzenie plików ADE 279 Zakończenie: przenoszenie bazy danych Access 97 na serwer SQL i do pliku ADP 280 ROZDZIAŁ 16. TWORZENIE INTERFEJSU UŻYTKOWNIKA DLA MICROSOFT SQL SERVER 281 Architektura klient-serwer: OLE DB kontra ODBC 281 Tworzenie połączenia z serwerem SQL 281 Tworzenie źródła danych ODBC (DSN) 282 Łączenie tabel 282 Wady tabel połączonych 283 Połączenie najlepszych metod: wypełnianie tabel podczas startu aplikacji 283 Procedury przechowywane i kwerendy przekazujące 284 Tworzenie raportów opartych na procedurach przechowywanych poprzez zapytania przekazujące 284 Raportowanie z serwera SQL w Accessie 286 Zaawansowane możliwości: przekazywanie parametrów do procedury przechowywanej w czasie działania programu 286 Dodatkowe filtrowanie danych raportu 287 Formularze w aplikacji 288 Formularze związane 288 Formularze niezwiązane 289 Zaawansowane właściwości: dostawca OLE DB dla serwera SQL 290 Następny zestaw wyników 290 Wykonywanie poleceń z parametrami 291 Długa droga 291 Użycie metody CreateParameters 292 Użycie Refresh 292 Obsługa zwracanych wartości 293 Wykonanie procedury bez obiektu Command 294 Użycie klasy Connection 294 Użycie klasy Connection w aplikacji 295 ROZDZIAŁ 17. INTERFEJS ACCESSA 2000 DO ORACLE'A 296 Dostęp do danych Oracle'a przez Accessa 296 Tabele połączone 297 Tworzenie ciągu połączenia ODBC 297 Tworzenia nazwy źródła danych 297 Koszt połączenia z Oracle'em 298 Kwerendy przekazujące (SPT) 298 Określanie właściwości kwerend przekazujących 299 Składnia kwerend przekazujących 299 Wielkość liter 299 Wyrażenie Select 300 Klauzula WHERE 300 Definiowanie zależności 300 Użycie znaków specjalnych 300 Użycie Null i Not Null 300 Tworzenie wyrażeń Insert 301 Tworzenie wyrażeń Update 301 Użycie Group By/Having 301 Funkcje w Oracle'u i Accessie 301 Ciągi 302 Łączenie 302 Initcap, Lower, Upper 302 Instr 303 LTrim/RTrim 303 Soundex 304 Substr 304 Decode 305 Obliczenia w Oracle'u 305 Ceil() 305 Floor() 305 Nvl() 306 Round() 306 Sign() 306 Trunc() 306 Greatest/Least 306 Obliczenia na datach 307 Arytmetyka 307 Sysdate 307 Add_Months 307 Months_Between 307 Next_Day() 308 To_Date() 308 Problem roku 2000 308 Poznajemy widoki i procedury przechowywane 309 Tworzenie widoków 309 Połączenie z Oracle'em poprzez ADO 310 Parametry 311 Tworzenie procedur przechowywanych 312 Uruchamianie procedury 313 Tworzenie niezwiązanego interfejsu do Oracle'a 313 Tworzenie niezwiązanego interfejsu 314 Tworzenie zmiennych globalnych 314 Ładowanie danych i inicjalizacja formularza 315 Programowanie przycisków sterujących 315 Zmiana danych Oracle'a przy użyciu formularza 317 Wstawienie danych do Oracle'a przy użyciu formularza 318 Zapisywanie danych do Oracle'a przy użyciu formularza 318 Usuwanie danych przy użyciu formularza 319 Zamykanie połączenia z Oracle'em 319 CZĘŚĆ VI WSPÓŁOPERATYWNOŚĆ 321 ROZDZIAŁ 18. UŻYCIE AUTOMATYZACJI ACTIVEX 322 Co to jest automatyzacja ActiveX 322 Dlaczego używamy automatyzacji 322 Różnice między serwerem automatyzacji a klientem automatyzacji 323 Określanie zasobów wymaganych przez automatyzację 323 Wielka trójka 323 Tworzenie i ustanowienie odwołania do innej aplikacji 323 Ustanawianie odwołania do innej aplikacji 323 Przegląd obiektów, właściwości i metod 324 Poznajemy strukturę obiektów 324 Użycie narzędzia Object Browser 324 Tworzenie zmiennej obiektowej 326 Odwołanie do pracującej aplikacji 326 Przypisywanie zmiennej obiektowej do aplikacji 326 Tworzenie egzemplarza aplikacji 327 Jednoczesne użycie funkcji GetObject i New 327 Użycie wczesnego i późnego łączenia typów 327 Użycie funkcji CreateObject 328 Kiedy nie można uzyskać odwołania do aplikacji 328 Co wtedy, gdy użytkownik ma inną wersję aplikacji? 328 Użycie metod i właściwości obiektów automatyzacji 329 Ustawianie właściwości obiektu 329 Wykonywanie metod obiektów 329 Zwalnianie obiektów automatyzacji 329 Łączymy wszystko razem 329 Zamykanie aplikacji serwera automatyzacji 330 Użycie właściwości UserControl do sprawdzenia, w jaki sposób została otwarta aplikacja 330 Użycie WithEvents w celu udostępnienia zdarzeń serwera automatyzacji 331 Uruchamiamy WithEvents 331 Techniki i wskazówki do automatyzacji 332 Ustanowienie odwołania, użycie wczesnego wiązania typów i słowa kluczowego New 332 Użycie istniejącego egzemplarza aplikacji, jeżeli jest ona uruchomiona 333 Wyłącz odświeżanie ekranu 333 Informacja o przetwarzaniu 333 Wykonywanie programu przez serwer automatyzacji 334 Użycie konstrukcji With/End With 334 Zwalnianie zmiennych obiektowych 334 Nie wyświetlaj okien dialogowych i komunikatów 334 Używaj obsługi błędów 334 ROZDZIAŁ 19. INTEGRACJA Z OFFICE 2000 335 Powody integracji z Office 2000 336 Użycie Worda 336 Użycie Excela 336 Użycie PowerPoint 336 Użycie Outlooka 336 Użycie Graph 337 Użycie MapPoint 337 Użycie FrontPage 337 Użycie Bindera 337 Wybór właściwego narzędzia 337 Wszędzie VBA 337 Użycie rejestratora makr do pisania kodu 338 Użycie makr automatycznych 339 Microsoft Forms 339 Object Browser 339 Nazwy klas aplikacji Office 340 Przykład automatyzacji 340 Automatyzacja Worda 341 Model obiektów Worda 342 Użycie szablonów Worda 342 Wstawianie danych do dokumentu Worda 343 Korespondencja seryjna 343 Zakładki 345 Zastępowanie 345 Przykłady kodu automatyzacji Worda 345 Formatowanie dokumentów 345 Użycie stylów dokumentu 346 Autokorekta 346 Autotekst 346 Autopodsumowanie 346 Widoki dokumentu 347 Spis treści 347 Przypisy 347 Nagłówki 347 Stopki 347 Hiperłącza 347 Tworzenie tabel 348 Ustawienia strony 348 Podgląd wydruku 348 Drukowanie dokumentów, kopert i etykiet 348 Pola 348 Informacje o dokumencie 349 Inne możliwości Worda 350 Automatyzacja Excela 350 Model obiektów Excela 350 Przykłady automatyzacji Excela 351 Formatowanie dokumentów Excela 351 Tworzenie wykresów 351 Użycie właściwości Parent 352 Automatyzacja PowerPoint 352 Model obiektów PowerPoint 353 Przykłady automatyzacji PowerPoint 353 Dodanie slajdu 353 Dodanie efektu przejścia 354 Wstawianie danych i formatowanie slajdów 354 Wstawienie rysunku do slajdu 354 Uruchamianie prezentacji 354 Automatyzacja Outlook 354 Model obiektów Outlook 355 Przykłady automatyzacji Outlook 355 Dodawanie i wyświetlanie folderów 355 Dodawanie nowego zadania i wyświetlenie zadań 356 Tworzenie wiadomości e-mail z załącznikiem 356 Tworzenie elementów Outlooka 357 Wyświetlanie domyślnych folderów 357 Wyświetlenie foldera publicznego 357 Szukanie elementu w Outlooku 357 Filtrowanie elementów w Outlooku 357 Automatyzacja Graph 358 Model obiektów Graph 358 Tworzenie wykresu 358 Przykłady automatyzacji Graph 359 Automatyzacja MapPoint 359 Model obiektów MapPoint 359 Przykłady automatyzacji MapPoint 360 Automatyzacja FrontPage 360 Model obiektów FrontPage 360 Przykłady automatyzacji FrontPage 361 Automatyzacja Bindera 362 Model obiektów Bindera 362 Przykłady automatyzacji Bindera 362 Zabezpieczanie dokumentów, szablonów i kodu programu 363 ROZDZIAŁ 20. UŻYCIE VISUAL BASIC Z ACCESSEM 364 Tworzenie komponentów ActiveX 364 Czym są komponenty ActiveX 364 Różnice między ActiveX EXE i ActiveX DLL 365 Tworzenie komponentu ActiveX 365 Kompilowanie biblioteki DLL 367 Użycie komponentu ActiveX cSound 368 Użycie komponentu w innych aplikacjach 369 Dystrybucja komponentów ActiveX 369 Instalowanie komponentu 369 Tworzenie programu instalacyjnego przy użyciu Package and Deployment Wizard 369 Rozprowadzanie plików przy użyciu kreatora Package and Deployment Wizard 373 Wpisy w rejestrze 375 Zgodność komponentów 375 Komponent obsługi błędów 376 Dane modułu obsługi błędów 377 Komponent cError 377 Tworzenie formantów ActiveX 377 Rodzaje formantów ActiveX 377 Atrybuty formantów ActiveX 378 Tworzenie programowych formantów ActiveX 378 Utworzenie projektu dla formantu ActiveX 378 Tworzenie interfejsu 379 Ustawianie właściwości projektu 380 Zapisywanie projektu 380 Dodawanie metod i zdarzeń 380 Użycie kreatora ActiveX Control Interface Wizard 380 Dodajemy kod do formantu ActiveX 382 Wywoływanie zdarzenia 382 Użycie zdarzenia ReadProperties 383 Testowanie formantu ActiveX w Visual Basicu 383 Użycie formantu Timer na formularzu Accessa 385 Tworzenie wielu formantów Timer 385 Rozprowadzanie formantu ActiveX Timer 386 Tworzenie okna właściwości 386 Użycie okna właściwości 387 Użycie formantu Timer w innych aplikacjach 387 Tworzenie formantów ActiveX interfejsu użytkownika 387 Tworzenie interfejsu użytkownika 387 Ustawienie właściwości projektu 388 Zapisywanie projektu 388 Testowanie formantu na formularzu Visual Basica 388 Użycie formantu cSlider na formularzu Accessa 388 Dystrybucja formantu ActiveX cSlider 389 Użycie formantu cSlider w innych aplikacjach 389 Tworzenie instalacyjnego pakietu internetowego 389 Użycie formantu cSlider na stronie WWW 391 CZĘŚĆ VII ZAGADNIENIA WIELODOSTĘPU 393 ROZDZIAŁ 21. ZAGADNIENIA WIELODOSTĘPU, SERWER PLIKÓW, BLOKOWANIE 394 Konflikty 394 Konfiguracja 395 Access i blokady Jet 395 Omówienie blokowania 396 Blokowanie stron kontra blokowanie rekordów 396 Plik LDB 397 Optymistyczne i pesymistyczne blokowanie rekordów 397 Blokowanie optymistyczne 397 Blokowanie pesymistyczne 397 Blokowanie rekordów 398 Właściwość RecordLocks w interfejsie związanym 398 Metody blokowania silnika Jet 398 Określanie stanu blokad 398 Sprawdzanie blokad 400 Użycie blokowania stron 401 Obsługa błędów blokowania 401 Ustawienia blokowania Accessa 401 Konflikty zapisu 401 Zablokowany rekord 402 Transakcje 402 Blokady Oracle/SQL Server 403 ROZDZIAŁ 22. REPLIKACJA I JRO 404 Kiedy użyć replikacji 404 Kiedy nie używać replikacji 405 Przystosowanie bazy do replikacji 405 Replikacja przy użyciu aktówki 405 Użycie interfejsu użytkownika 406 Wybór między obiektami lokalnymi i replikowanymi 408 Planowanie topologii replikacji 409 Wybór schematu sterowanego 411 Synchronizacja bezpośrednia 411 Synchronizacja pośrednia 411 Wybór schematu niesterowanego 411 Jet i model obiektowy replikacji 411 Poznajemy JRO 412 Opis metod i właściwości JRO 413 Właściwość ActiveConnection 413 Właściwość ConflictFunction 413 Właściwość ConflictTables 415 Właściwość DesignMasterID 416 Obiekty repliki 416 Właściwość ReplicaID 416 Właściwość ReplicaType 416 Właściwość RetentionPeriod 416 Właściwość Visibility 417 Metoda CreateReplica 417 Metoda GetObjectReplicability 418 Metoda MakeReplicable 418 Metoda PopulatePartial 419 Metoda SetObjectReplicability 420 Metoda Synchronize 420 Kolekcja Filters 421 Właściwość Count 421 Metoda Item 421 Metoda Append 422 Metoda Delete 422 Metoda Refresh 422 Obiekt Filter 422 Właściwość FilterCriteria 422 Właściwość FilterType 422 Właściwość TableName 423 ROZDZIAŁ 23. BEZPIECZEŃSTWO 424 Elementy bezpieczeństwa 424 Zabezpieczenie bazy danych hasłem 424 System bezpieczeństwa grupy roboczej 425 Tworzenie grupy roboczej 426 Użytkownicy i grupy 427 Omówienie domyślnych ustawień użytkowników i grup 428 Tworzenie użytkowników 428 Ustawianie i zmiana hasła użytkownika 429 Tworzenie grup 429 Przypisywanie użytkowników do grup 430 Rozróżnianie między domyślnymi i specjalnymi grupami i użytkownikami 430 Poznajemy uprawnienia 430 Tworzenie systemu bezpieczeństwa przy użyciu opcji startowych 432 Zagadnienia bezpieczeństwa przy użyciu replikacji 432 Ochrona podzielonych baz danych 433 Opcja With OwnerAccess 434 Bezpieczeństwo systemu klient-serwer 434 Zarządzanie użytkownikami 434 Wyliczanie grup i użytkowników oraz wyświetlanie przynależności 435 Identyfikacja bieżących użytkowników za pomocą ADOX 436 Wyszukiwanie użytkowników z pustym hasłem 437 Ustawianie i usuwanie hasła 438 Zarządzanie grupami 438 Zarządzanie właściwością obiektów 438 Zarządzanie wieloma aplikacjami 438 Użycie SQL 439 Create 439 Add User 439 Grant/Revoke 439 Drop 440 Zabezpieczanie bazy danych krok po kroku 440 Częste błędy bezpieczeństwa 440 CZĘŚĆ VIII PUBLIKOWANIE W SIECI ZA POMOCĄ ACCESSA 2000 442 ROZDZIAŁ 24. KONFIGURACJA SERWERA WWW DLA PUBLIKOWANIA W SIECI WWW 443 Środowisko programistyczne a środowisko produkcyjne 443 Wybór platformy 444 Personal Web Server i Peer Web Services 444 Internet Information Server 444 Co to jest Option Pack 445 Uruchomienie serwera WWW 446 Instalacja 446 NT Option Pack dla Windows 95/98 446 Dostępne komponenty instalacji 446 Opcje instalacji: minimalna, typowa i niestandardowa 448 Microsoft Transaction Server 2.0 449 Co to jest broker transakcji? 449 Zarządzanie i konfiguracja serwera WWW 450 Personal Web Manager 450 Microsoft Management Console 451 Konfiguracja Internet Information Server 451 Zabezpieczanie aplikacji WWW 455 Różnice pomiędzy witryną a katalogiem wirtualnym 456 Co to jest IUSER ? 457 Typ systemu plików 457 Struktura katalogów i wymagane uprawnienia 458 ASP/HTML – położenie i uprawnienia 458 Bazy danych – położenie i uprawnienia 459 ROZDZIAŁ 25. PRZENOSZENIE ACCESSA 2000 DO SIECI WWW ZA POMOCĄ KOMPONENTÓW SIECIOWYCH OFFICE 460 Czym są komponenty sieciowe Office 460 Co potrafią komponenty sieciowe Office 461 Wymagane licencje na użycie komponentów sieciowych 461 Użycie formantu Office Arkusz 461 Rozpoczynamy 461 Użycie formantu w Accessie 462 Użycie formantu Office Wykres 463 Rozpoczynamy 464 Użycie formantu w Accessie 464 Użycie formantu Office Tabela przestawna 465 Rozpoczynamy 466 ROZDZIAŁ 26. UŻYCIE STRON DOSTĘPU DO DANYCH 467 Czym są strony dostępu do danych? 467 Architektura oraz wymagania stron dostępu do danych 467 Tworzenie Twojej pierwszej strony dostępu do danych 468 Oglądanie strony dostępu do danych 470 Tworzenie interaktywnych odnośników 471 Łączenie komponentów sieciowych Office z DAP 472 Dodanie komponentu sieciowego Arkusz Excel 473 Dodanie komponentu sieciowego Wykres 473 Skrypty w stronach dostępu do danych 474 Zmiana źródła danych w trakcie działania strony 475 ROZDZIAŁ 27. PUBLIKOWANIE W SIECI PRZY UŻYCIU ACCESSA 2000 I ACTIVE SERVER PAGES 477 Użycie Active Server Pages 477 Architektura Active Server Pages 478 Active Server Pages kontra CGI 478 Uruchomienie stron ASP 478 Rozpoczynamy pracę z Active Server Pages 479 Konstrukcja kodu ASP 480 Ograniczenia eksportu stron ASP 481 Active Server Pages 481 Silnik ASP 481 Skrypty wykonywane na serwerze 481 Użycie VBScript na stronach ASP 484 Obiekty aplikacji i sesji 486 Użycie obiektu aplikacji 486 Użycie obiektu sesji 486 Użycie obiektów żądań i odpowiedzi 486 Obiekt Response 487 Response.Redirect 487 Response.Write 487 Obiekt Request 487 Plik global.asa 487 Przykłady użycia obiektów ASP 488 Użycie ADO w aplikacjach ASP 489 Przykład: tworzenie strony WWW dostępnej dla członków grupy 490 Publikacja w sieci z Accessa 2000 przy użyciu XML 494 Podstawy XML 494 Programowe tworzenie pliku XML 496 Tworzenie wykresów przy użyciu formantu Wykres 498 Część I Projektowanie bazy danych Rozdział 1. Co nowego w Accessie 2000 W tym rozdziale: ? Nowy interfejs użytkownika. ? Zmiany w VBE. ? Strony dostępu do danych. ? Podarkusze danych. ? Autokorekta nazw. ? ADO jako domyślny system dostępu do danych. ? Współpraca online. ? Access jako interfejs użytkownika dla SQL Server. Gdy na rynku pojawiła się pierwsza wersja programu Access, trudno było przypuszczać, że kiedyś stanie się on tak potężnym narzędziem jakim jest Access 2000. Ci, którzy korzystali z Accessa 1.0, pamiętają z pewnością aplikację o następujących cechach: maksymalnej wielkości pliku ograniczonej do 128 MB, braku zdolności transakcyjnych, braku narzędzi programistycznych z prawdziwego zdarzenia, statycznych paskach narzędzi, braku integralności referencyjnej oraz bardzo niskiej wydajności. Pomimo wyżej wymienionych wad w owym czasie program ten nie miał sobie równych. Zawdzięczał to łatwym w obsłudze narzędziom konstrukcyjnym, dynasetom oraz konstruktorowi kwerend. Z każdym uaktualnieniem Access stawał się coraz potężniejszym i bardziej użytecznym narzędziem oraz systemem rozwoju. Użytkownicy oraz programiści pracujący z Accessem z zadowoleniem przyjmowali kolejne ulepszenia silnika bazy danych aż do wersji 4.0. Wówczas to, Access posiadał już przetwarzanie transakcyjne, integralność referencyjną, zdolności replikacyjne, ulepszone zarządzanie współbieżnością, a ponadto działał szybciej i dużo stabilniej. Ponadto program początkowo posiadający proste makra języka Access VB został wyposażony w pełną obsługę VBA wraz ze środowiskiem rozwoju prawie identycznym z Visual Studio w wersji 6.0. Poprawiono także interfejs narzędzi. Obsługa narzędzi innych producentów oraz formantów ActiveX znacznie poszerzyły dostępne programistom możliwości projektowania. Wraz z pojawieniem się na rynku Accessa 95 i 97 programiści uzyskali możliwość tworzenia wielu kopii formularzy. Wersja 97 umożliwiła im również korzystanie z Active Server Pages, rozszerzając tym samym zasięg Accessa na Internet. Na przestrzeni lat, usprawnienia Accessa można liczyć w setkach. Dziś ulepszenia, jakie wprowadzono w Accessie 2000, są naprawdę zadziwiające. Różnice między Accessem 2000 a jego poprzednią wersją są prawie tak duże jak różnice między jego pierwszą wersją i Accessem 97. Nie ulega wątpliwości, iż miliony docelowych użytkowników i programistów Accessa uznają jego nową wersję za elastyczne i niezwykle użyteczne narzędzie. Z pewnością również kolejne miliony przekonają się o jego zaletach i zaczną z niego korzystać w nadchodzących miesiącach i latach. Nowy interfejs użytkownika Pierwszą rzeczą, jaką zauważysz po uruchomieniu Accessa 2000, jest jego nowy interfejs. Microsoft postanowił ujednolicić graficzny interfejs użytkownika we wszystkich swoich aplikacjach, włączając w to Access. Okno bazy danych posiada pasek zawierający grupy obiektów dostępnych dla programisty, co upodabnia Access do programu Microsoft Outlook. Nie jest to tylko zabieg kosmetyczny. Dzięki temu możesz tworzyć dowolne, logiczne grupy, ze skrótami do właściwych obiektów. Przykładowo, możesz utworzyć grupę „Zamówienia i Sprzedaż”, a następnie w obrębie tej grupy umieścić skróty do kwerend, formularzy, raportów, stron, makr i modułów powiązanych z zamówieniami i sprzedażą. Dzięki temu unikniesz czasochłonnych poszukiwań wśród wszystkich obiektów. Tę przydatną cechę ilustruje rysunek 1.1. Rysunek 1.1. Wszystko, co jest związane z zamówieniami i sprzedażą, znajduje się w jednym miejscu Mniej widoczną, lecz równie ważną zmianą, jest wyświetlanie w menu Accessa 2000 jedynie najczęściej używanych poleceń. Dwukrotne kliknięcie menu lub kliknięcie znaku rozwijającego spowoduje wyświetlenie pozostałych poleceń. Czynność tę przedstawiliśmy na rysunku 1.2 Rysunek 1.2. Rozwijane menu pomagają zapobiegać bałaganowi Kreatory służące tworzeniu i edycji obiektów również mają odpowiednie, przyporządkowane im miejsca, dzięki czemu zawsze wiesz, gdzie się znajdują. Ta kontekstowa dostępność pozwoli programistom zaoszczędzić czas. Zwiększono również zestaw dostępnych funkcji obecnej już od dawna w systemie Windows opcji – schowka. Teraz możesz skopiować do schowka kilka elementów, a następnie zgodnie z potrzebą wklejać je do dokumentu. Dzięki temu znacznie łatwiej jest zmieniać układ funkcji lub ustawiać właściwości obiektu. Zmiany w VBE Kolejną kosmetyczną zmianą jest wygląd środowiska Visual Basic (VBE – ang. Visual Basic Environment). Teraz, zamiast otwierać moduł, jakby to był zwykły plik tekstowy, Access posiada osobną przestrzeń roboczą służącą do pisania, usuwania błędów oraz uruchamiania projektów Accessa 2000. Tym samym środowisko programistyczne Accessa osiągnęło poziom pozostałych programów pakietu Office i zawiera teraz zintegrowane środowisko programowania (IDE – ang. Integrated Development Environment). Jeśli kiedykolwiek pracowałeś z VBA w Office 97 lub z Visual Basic, nowe, przedstawione na rysunku 1.3, VBE Accessa 2000 nie będzie Ci obce. Dzięki możliwości umieszczania pasków narzędzi i okien w dowolnym miejscu będziesz mógł dostosować miejsce pracy do swoich potrzeb. Jedno z okien może zawierać kod programu, który piszesz, natomiast w innym możesz przeglądać właściwości dowolnego obiektu. W trzecim oknie mogą być wyświetlone formularze, raporty, moduły i klasy w bazie danych. W jeszcze innym oknie, takie narzędzia jak okienko bezpośrednie lub okienko zmiennych lokalnych (które w tej wersji są osobnymi oknami) pomogą Ci usuwać błędy w kodzie programu. W przeciwieństwie do VB wszystkie moduły utworzone w tym osobnym, zintegrowanym środowisku przechowywane są w pliku .MDB wraz ze wszystkimi obiektami bazy danych. Jednakże, możesz z łatwością importować i eksportować pliki typu *.bas, *.cls i *.frm do i z Accessa 2000. Rysunek 1.3. Środowisko VBE jest teraz w dużym stopniu konfigurowalne Strony dostępu do danych Możliwości, jakie Access stwarza programistom, również zostały rozszerzone o nowy obiekt – strony dostępu do danych (DAP – ang. Data Access Pages). Umożliwiają one użytkownikom tworzenie stron sieci Web, powiązanych z danymi w taki sam sposób jak formularze lub raporty. Wystarczy umieścić na stronie kilka specjalnych formantów, ustawić kilka właściwości, zapisać je w intra- bądź Internecie, a inni użytkownicy będą mogli korzystać z nich za pomocą przeglądarki. Strony te mogą zawierać również pogrupowane dane (ang. Grouped Data Access Pages). Takie strony umożliwiają użytkownikom interaktywne zagłębienie się w dane przy użyciu przeglądarki. Może okazać się, że strony dostępu do danych są najszybszym sposobem na współdzielenie danych i zestawu funkcji interfejsu z użytkownikami. Strony te mogą także być alternatywnym sposobem rozpowszechniania plików typu MDE. Elementy sterujące stron dostępu do danych przedstawionych na rysunku 1.4 korzystają z wewnętrznych elementów HTML oraz formantów COM. Posiadają one także bogaty zasób obiektów i współpracują z Visual Basic Scripting Edition, skryptami Java oraz komponentami Office Web Components. Oznacza to, iż nabyte uprzednio umiejętności projektowania stron sieci Web mogą być z łatwością przeniesione do Accessa 2000. Podarkusze danych Kolejną z cech interfejsu użytkownika Accessa 2000, która z pewnością będzie bardzo użyteczna, są podarkusze danych. Dzięki nim możesz praktycznie bez wysiłku tworzyć edytowalne, hierarchiczne grupy danych, rozszerzane przez kliknięcie małego znaku plus. Rysunek 1.4. Dane i zestaw funkcji mogą być przeglądane z poziomu aplikacji lub przeglądarki Rysunek 1.5. Kliknięcie znaku plus powoduje wyświetlenie powiązanych danych Grupy te możesz umieścić w dowolnym miejscu w widoku arkusza danych. Uzyskane dzięki temu trójwymiarowe spojrzenie na dane z pewnością znajdzie wiele zastosowań i może stać się szybką i prostą alternatywą dla formantu Tree. Autokorekta nazw Kolejną bardzo przydatną cechą Accessa 2000 jest autokorekta nazw. W poprzednich wersjach Accessa musiałeś bardzo uważać podczas zmiany nazwy obiektu, gdyż Access nie rozpoznawał nowej nazwy dopóty, dopóki nie uaktualniłeś wszystkich obiektów z nią powiązanych. Access 2000 automatycznie wykona to męczące zadanie za Ciebie, więc gdy uznasz, że dane pole powinno nazywać się inaczej, możesz zmienić jego nazwę w dowolnym momencie, a aplikacja będzie wciąż działać poprawnie. ADO jako domyślny system dostępu do danych Gdy spojrzymy do wewnątrz, w Accessie zmieniono domyślny system dostępu do danych. Zamiast znanych, lecz pamięciochłonnych obiektów Data Access (DAO), do pobierania i zarządzania danymi Access używa obiektów Active Data (ADO). Korzyści płynące z ADO są bardzo liczne: prostszy interfejs, płaska struktura, użycie tych samych technik i interfejsów między podobnymi źródłami danych, możliwość pobierania i zarządzania danymi z innych źródeł niż tylko programy typu RDBMS, a także zapowiedź większej wydajności i rozszerzonych opcji. Mimo iż Access współpracuje z obiektami DAO, Microsoft nie będzie już rozbudowywał tego systemu. Tak więc, jeśli nie miałeś jeszcze okazji pracować z ADO, szczegółowy opis tego zagadnienia znajdziesz w rozdziale 6. „Wprowadzenie do obiektów danych ActiveX” i 7. „Zaawansowane ADO”. Oprócz ADO, również dostawcy OLEDB dostarczają podobnych interfejsów dla szerokiej gamy źródeł danych w standardzie Microsoft’s Universal Data Access. Ustawienia dla dostawców OLEDB mogą być również zapisane w pliku typu Universal Data Link (UDL), co znacznie ułatwia kontrolowanie (i zmianę) źródeł danych. Współpraca online Współpraca online jest szczególnie wartościowa dla programistów, którzy współpracują ze sobą mimo dzielącej ich odległości. Po rozpoczęciu spotkania programiści mogą wymieniać uwagi o projektach za pomocą serwera listy, a także korzystać z takich opcji jak wspólna tablica, aby efektywnie wyrażać swoje pomysły. Access jako interfejs użytkownika dla SQL Server Bez wątpienia najciekawszą z nowych opcji Accessa 2000 jest nowy typ projektu aplikacji: Microsoft Access Project (*.adp). Projektom tym, będącym zapowiedzią nadchodzącej ery Accessa, poświęcimy w tej książce dużo miejsca. Access był zawsze zdalną bazą danych działającą w ramach środowiska serwera plików i był ograniczony do ilości danych, z którą jego silnik Jet mógł sobie poradzić, oraz ilości użytkowników, których mógł obsłużyć. Microsoft Access Project nie posiada takich ograniczeń, gdyż jest prawdziwym interfejsem użytkownika dla SQL Server i Microsoft Data Engine. Dzięki obsłudze OLEDB, Access 2000 może całkowicie pominąć Jet i współpracować bezpośrednio z innymi silnikami baz danych. Podczas tworzenia bazy danych w Accessie 2000 użytkownik może utworzyć Project, a następnie wybrać między dołączonym do pakietu Office 2000 Microsoft Data Engine (MSDE) a SQL Server 6.0 i 7.0. Każdy z nich jest w stanie obsługiwać tysiące użytkowników i terabajty danych. Access jest środowiskiem rozwoju i administrowania dla SQL Servera, a utworzona aplikacja staje się prawdziwym klientem w relacji klient-serwer. Access Project nie zawiera żadnych danych, tabel czy kwerend. Jest bezpośrednio połączony z zapleczem i umożliwia tworzenie, przeglądanie i modyfikowanie tabel w bazie, przechowywanych procedur, widoków i diagramów bazy danych. W porównaniu do poprzednich wersji Accessa możemy mówić o radykalnej zmianie. Mimo iż wielu programistów dołączało tabele z SQL Server i Oracle, kwerendy na nich oparte były wykonywane lokalnie (uruchomienie kwerendy opartej na dołączonej tabeli powoduje przeniesienie danych na komputer klienta). Niektórzy programiści tworzyli kwerendy przekazujące, dzięki czemu serwer wykonywał większość obliczeń, ale to dość specyficzny przypadek. Dołączona tabela nie mogła być modyfikowana, a stworzenie i obsługa widoków i przechowywanych procedur, pobranych za pomocą kwerendy przekazującej, mogły wymagać osobnych narzędzi administracyjnych. Ograniczenia te powodowały opóźnienia w realizacji projektu i wymagały zaangażowania dodatkowych pracowników wówczas, gdy nie było to pożądane. Access Projects umożliwiły programistom tworzenie całego projektu aplikacji klient-serwer samemu i bez użycia dodatkowych narzędzi. Przedstawiciele Microsoftu są przekonani o tym, iż ta opcja zyska sobie aprobatę użytkowników i przyczyni się do sukcesu tego programu. Aby było to możliwe, typy danych Accessa dostosowano do SQL Server, uaktualniono składnię SQL, by była zgodna ze standardami ANSI, a także uaktualniono kreatory i narzędzia wspomagające nową architekturę klient-serwer. Stworzono także nowe narzędzia służące do tworzenia i zarządzania obiektami po stronie serwera w widoku Projekt klienta. Także inne zwykłe czynności administracyjne, jak zabezpieczenia, sporządzanie kopii zapasowych i replikacja, mogą być zarządzane przez Access 2000. Rozdział 2. Planowanie procesu rozwoju W tym rozdziale: ? Określenie wymagań. ? Architektura. ? Planowanie rozwoju. ? Konstrukcja. W pozostałych rozdziałach tej książki opisane są wszystkie potężne narzędzia i opcje, jakie oferuje Access 2000. Jednakże, nawet po opanowaniu tego materiału, gdy będziesz już świetnym programistą, sukces Twoich projektów wciąż będzie niepewny, jeśli nie zrozumiesz, jak ważny dla ich powodzenia jest proces rozwoju. Nawet, jeśli świetnie programujesz, to efektem braku dobrze zaplanowanego procesu lub zgranej grupy współpracowników może być niezadowalający wynik projektu. W tym rozdziale zawarliśmy kilka kluczowych informacji oraz czynności dotyczących zespołu i procesu rozwoju. Chcielibyśmy pomóc Ci w budowaniu udanych projektów, poprzez stworzenie Twojego własnego, efektywnego i opartego na sprawdzonych metodach procesu rozwoju. Opisanie tych zagadnień w pełni zajęłoby nam całą książkę. Udany proces rozwoju skupia się na czterech kluczowych etapach projektu: Wymaganiach, Architekturze, Planowaniu Rozwoju oraz właściwej fazie Konstrukcji. W fazie Wymagania, będziesz zbierał i analizował rzeczywiste potrzeby użytkowników. W fazie Architektura wybierzesz układ, technologie i narzędzia rozwoju, które w najlepszy sposób te potrzeby zaspokoją. Podczas fazy Planowanie rozwoju sporządzisz plan rozwoju, który będzie opisywał sposób, w jaki projekt będzie wdrożony, ustalisz niezbędną liczbę programistów oraz koszty całego przedsięwzięcia. Ostatnia faza rozwoju to tworzenie aplikacji. Rysunek 2.1 przedstawia cztery fazy procesu rozwoju, począwszy od określenia wymagań, aż do tworzenia aplikacji. Zawiera on również niektóre z edycji programu, wypuszczane podczas tej fazy. W tym rozdziale szczegółowo scharakteryzujemy każdą z faz. Rysunek 2.1. Proces rozwoju Określenie wymagań Określenie i analiza wymagań jest najważniejszą czynnością wpływającą na jakość aplikacji. Wielokrotnie byliśmy świadkami projektów, które upadały na skutek nieprecyzyjnie bądź błędnie zdefiniowanych wymagań. Dlaczego faza wymagań jest tak ważna? Prawidłowo zidentyfikowane i przeanalizowane wymagania pozwolą zmniejszyć liczbę nieprzewidzianych zmian, które trzeba będzie później wprowadzić. Eksperci z przemysłu software’owego stwierdzili, że koszty ponoszone na wprowadzanie zmian, rosną o mnożnik zawierający się między 5 a 10, podczas przejścia na każdy kolejny etap procesu rozwoju. Przykładowo, jeśli klient zauważy błąd w wymaganiach, który zostanie poprawiony w fazie wymagań, zmiana zajmie godzinę. Jeśli błąd zostanie zauważony dopiero po włączeniu tej opcji w projekt, wprowadzenie zmiany zajmie 10 godzin. Jeśli element ten został już zintegrowany i przetestowany z resztą aplikacji, naprawa błędu może potrwać 50 godzin. Jeśli problem wynikł dopiero po dostarczeniu aplikacji do klienta, jego rozwiązanie zajmie blisko 100 godzin. Dlaczego aż tak dużo? Po pierwsze, wymagania powinny być uaktualniane. Projekt i kod programu muszą być analizowane, aby ocenić czy zmiany są konieczne. Wówczas zmiany te muszą być wprowadzone, a różne moduły, kwerendy, formularze i raporty przetestowane. Sama aplikacja musi być osobno przetestowana, aby mieć pewność, że zmiany odniosły przewidywany skutek i nie spowodowały wystąpienia kolejnych błędów. Wreszcie, poprawiona aplikacja musi być ponownie dostarczona do każdego z użytkowników. Oczywiście, podane tu mnożniki to średnie wartości dla tej gałęzi przemysłu, a nie wartości absolutne. W zależności od rozmiaru zmian, koszty mogą być od nich niższe bądź wyższe. Jeśli błąd odbił się negatywnie na działalności klienta, koszty mogą być astronomiczne. Odnalezienie rzeczywistego problemu Określenie wymagań należy rozpocząć od ustalenia zakresu aplikacji. Nie ulega wątpliwości, że klient ma problem, który, jak sądzi, może być rozwiązany za pomocą programu komputerowego. Jednak klient nie zawsze może właściwie zdefiniować ów problem. Aby zilustrować proces rozwoju, przez cały ten rozdział będziemy używać przykładu „Sprawozdanie o kosztach pracowników”. Przykładowo, klient może zamówić dla swoich pracowników system, który będzie służył do wprowadzania i drukowania raportów o poniesionych kosztach. Po przeprowadzeniu analizy możesz stwierdzić, że rzeczywistą potrzebą klienta jest automatyzacja wprowadzania, podziału, zatwierdzania i przetwarzania całego procesu związanego z raportami o kosztach. Odnajdywanie takich różnic należy do twoich zadań. Czasami klient myśli o rozwiązaniu, które jest zbyt małe, aby rozwiązać jego problem. Równie często zdarza się, że klient myśli o rozwiązaniu, które jest zbyt obszerne i złożone. Aby zrozumieć jak aplikacja współdziała z pozostałymi częściami działalności klienta, powinieneś koniecznie poszerzyć zasięg procesu określania wymagań ponad oczekiwany zysk z jej funkcjonowania. Śledztwo Aby określić, jaki problem rzeczywiście wymaga rozwiązania i właściwie ustalić wymagania, musisz na chwilę stać się detektywem. Oto kilka pomocnych wskazówek: ? Gdy poszukujesz kluczowych informacji o funkcjonowaniu procesu, nigdy nie opieraj się na opiniach innych osób. ? Wielokrotnie w procesach handlowych można wyróżnić oficjalny sposób, w jaki proces powinien przebiegać oraz sposób, w jaki rzeczywiście przebiega. Powinieneś poznać obydwa. ? Bądź otwarty i słuchaj uważnie. Pierwsze Twoje pomysły (i klienta) na rozwiązanie problemu powinny zostać zapisane i odłożone, dopóki nie zostaną potwierdzone za pomocą obserwacji i analiz. ? W tabeli 2.1 znajdziesz przykłady typowych wymagań klientów. Pierwszym etapem śledztwa jest określenie wszystkich uczestników procesu. Przez uczestnika rozumiemy osobę, grupę lub dział, który jest zainteresowany procesem lub aplikacją. Uczestnikami są menedżerowie, osoby nadzorujące oraz pracownicy bezpośrednio odpowiedzialni za każdy z zaangażowanych w proces działów. Uczestnikami są także ci użytkownicy aktualnego procesu, którzy staną się użytkownikami tworzonej przez Ciebie aplikacji. Niektóre z grup uczestników będą tak duże, że będziesz je musiał ograniczyć tylko do kilku przedstawicieli. W trakcie trwania śledztwa możesz odkryć nowych uczestników, których będziesz musiał dołączyć. Dodatkowym zyskiem z uwzględnienia uczestników w procesie określania wymagań jest uzyskany dzięki temu wzrost ich poczucia przynależności do nowego systemu. Zauważysz większą chęć do współpracy i pomoc przy dostarczaniu i uruchamianiu aplikacji u klienta. Kontynuujmy nasz przykład sprawozdania o kosztach. Zechcesz przeprowadzić wywiady z kilkoma reprezentatywnymi użytkownikami, z których część rzadko ponosi jakiekolwiek wydatki, część często podróżuje, a także z kilkoma przeciętnymi użytkownikami. Później porozmawiasz z kilkoma osobami z działu płac, które co miesiąc zajmują się przetwarzaniem tych sprawozdań oraz przedstawionych rachunków. Teraz rozpoczyna się prawdziwe śledztwo. Porozmawiaj z każdym uczestnikiem. Zadawaj wiele pytań, słuchaj uważnie i sporządzaj notatki. Pytaj, jak działa aktualny system oraz co im się w nim podoba lub nie. Zapytaj także, co chcieliby zmienić. Z tych notatek możesz ułożyć prawdziwy obraz aktualnego procesu i sposobu działania firmy. Przeanalizuj aktualny proces i zanotuj wszystkie potencjalne gniazda zapalne i wąskie gardła. Pamiętaj także o zebraniu wszystkich wad, zalet, życzeń i marzeń, o których dowiedziałeś się podczas wywiadów. Diagramy procesu Diagramy procesu są doskonałym sposobem na opisanie sposobu działania procesu handlowego. Przedstawiony na rysunku 2.2 diagram ilustruje przykład sprawozdania o kosztach. Diagramy te przedstawiają interakcje zachodzące między głównymi osobami, grupami i działami zaangażowanymi w proces. Poszczególne kroki lub czynności w procesie następują od lewej do prawej i przedstawione są za pomocą prostokątów. Kroki te pochłaniają wpływy z lewej strony i powodują powstawanie wyników z prawej. Pionowe strzałki oznaczają wszystkie wewnętrzne zasady handlowe bądź zewnętrzne uregulowania i ograniczenia. Romby przedstawiają podejmowane w trakcie trwania procesu decyzje. Jako że pozioma oś przedstawia czas, wszelkie opóźnienia i czasochłonne czynności są łatwe do zidentyfikowania. Po przeanalizowaniu przedstawionego na diagramie aktualnego procesu oraz potrzeb uczestników można narysować drugi diagram, który będzie ilustrował proces po wprowadzeniu zmian. Rysunek 2.2. Przykład diagramu procesu rozliczania kosztów podróży Diagramy procesu, takie jak ten na rysunku 2.2, są bardzo proste w tworzeniu i zrozumiałe dla wszystkich uczestników. Po zobaczeniu diagramu wielu z uczestników będzie zaskoczonych stopniem skomplikowania i złożonością aktualnego procesu. Jeśli sporządzanie diagramu procesu rozpoczniesz odpowiednio wcześnie, będziesz mógł go modyfikować podczas rozmów z uczestnikami. Diagramy procesu mogą znacznie ułatwić Ci stworzenie scenariusza i prowadzenie wywiadów. Każdy uczestnik będzie mógł teraz wyjaśnić i pokazać szczegóły całego procesu. Możesz uznać za przydatne stworzenie hierarchii diagramów procesu. Na najwyższym poziomie znajdzie się diagram opisujący cały proces, a poniżej będą diagramy ilustrujące w powiększeniu poszczególne jego etapy. Podprocesy mogą być przedstawione ze szczegółami na osobnych diagramach procesu. Podejście hierarchiczne często ułatwia zrozumienie skomplikowanych diagramów. Każdy diagram procesu powinien być tworzony na dużej kartce papieru, a nie przy użyciu komputera. Rysowanie na papierze zabiera mniej czasu i umożliwia większą interakcję. Jest także mniej uciążliwe i bardziej czytelne. Aby ograniczyć konieczne poprawki i zmiany, jako elementów procesu można używać naklejanych karteczek. Po otrzymaniu ostatecznego diagramu procesu można go przerysować przy użyciu Microsoft Worda 2000 lub Visio. Identyfikacja zakresu projektu Współpracuj z klientem, aby właściwie określić zakres aplikacji. Pamiętaj, że chodzi tu o zakres długoterminowy, a nie koncentrujący się na tej fazie projektu. W przykładzie ze sprawozdaniem o kosztach programiści i decydenci doszli do porozumienia co do zakresu aplikacji. Uzgodnili, iż aplikacja powinna zautomatyzować rozliczanie zaliczek, zgłaszanie zapotrzebowania na delegacje oraz cały proces zgłaszania kosztów począwszy od pojawienia się zapotrzebowania na delegację u pracownika, aż do uwzględnienia rachunków za podróż w dziale księgowości. Zdecydowano również pominąć systemy księgowe i sam proces rezerwowania biletów. Te elementy nie zostały uwzględnione w zakresie aplikacji. Spisywanie wymagań Przedstawienie wymagań na piśmie jest najlepszym sposobem komunikacji pomiędzy programistą a klientem. Praktyka ta umożliwia wyeliminowanie nieporozumień. Forma pisemna nie oznacza, iż musi to być koniecznie dokument oficjalny. Istnieje wiele skutecznych sposobów na przekazywanie wymagań: przykładowe raporty, formularze, diagramy procesu lub rysunki. Spisywanie wymagań nie jest wcale trudne. Wystarczy zadbać o to, by klient mógł bez trudu je przeczytać i zrozumieć. Oto jakie pytania możesz zadać, aby sprawdzić, czy właściwie zidentyfikowałeś wymagania: ? Czy opisuje potrzebę, czy raczej sposób jej realizacji? ? Czy może być zweryfikowane po jego wprowadzeniu? ? Czy jest jednoznaczne? ? Czy w pełni opisuje potrzebę? ? Czy razem z pozostałymi wymaganiami stanowi jednolitą całość? W tabeli 2.1 umieściliśmy przykłady wielu rodzajów wymagań, których użycie powinieneś rozważyć. Wymagania te posłużą jako część umowy. Wydrukuj tę wersję dokumentacji wymagań i poproś klienta o jej podpisanie. Ten dokument stanie się podstawą dalszego rozwoju aplikacji. Od tego momentu musisz zacząć zastanawiać się nad wpływem zmian w wymaganiach na planowany budżet i harmonogram. Pamiętaj, aby po dokonaniu zmian zweryfikować budżet, harmonogram i wszystkie pozostałe powiązane wymagania oraz dokumentację projektu. Utwórz bazę danych zawierającą wszystkie wymagania. Dla każdego z wymagań dołącz numer identyfikacyjny, typ, opis, datę, źródło, zysk oraz sposób weryfikacji wymagania po jego implementacji, wagę i inne. Tabela 2.1. Typy wymagań Typ wymagań Opis Przykład Funkcjonalne Wymagania te opisują żądane funkcje lub cechy oraz zasady handlowe, które ich dotyczą Użytkownik będzie w stanie nadać priorytet klienta na: Krytyczny, Wysoki, Średni, Niski Tabela 2.1. Typy wymagań (ciąg dalszy) Typ wymagań Opis Przykład Wydajność Wymagania dotyczące wydajności zawierają: Szybkość, Czas reakcji, Pojemność, Wielkość bazy danych Baza danych powinna poprzez zakładową sieć LAN obsługiwać do 20 użytkowników, ze standardowym czasem odpowiedzi wysokości 200 ms Bezpieczeństwo Wymagania dotyczące bezpieczeństwa obejmują ograniczenia w użytkowaniu i dostępie do opcji aplikacji oraz danych Wszyscy użytkownicy muszą się do aplikacji logować. Każdy użytkownik będzie członkiem jednej z następujących grup bezpieczeństwa: Użytkownik, Administrator, Menedżer Skalowalność Skalowalność dotyczy zdolności do powiększania ilości danych, użytkowników, witryn lub częstotliwości zbierania danych Aplikacja musi obsługiwać 50 aktualnych użytkowników oraz dodatkowo 50 użytkowników, którzy zostaną dołączeni na przestrzeni najbliższych dwóch lat Rozszerzalność Wymagania dotyczące rozszerzalności charakteryzują zdolność do poszerzania aplikacji o dodatkowe opcje w kolejnych wersjach. Aplikacja będzie tak skonstruowana i zaimplementowana, aby można było dodać obsługę faktur klientów Konfigurowalność Konfigurowalność mierzy łatwość, z jaką parametry aplikacji mogą być zmieniane przez klienta, bez konieczności ingerencji zespołu programistów Administrator będzie miał możliwość corocznego uaktualniania stawek ubezpieczeniowych Kompatybilność Kompatybilność to zdolność aplikacji do jej instalowania i funkcjonowania w różnych środowiskach sprzętowych i programowych, a także do interakcji z innymi aplikacjami Program będzie zainstalowany w systemach Win95, Win98 i Win NT 4.0 Workstation, z minimum 8MB pamięci oraz 200MB dostępnej przestrzeni dyskowej Dostępność Dostępność służy do określenia ile godzin lub jaką część czasu aplikacja jest w stanie wykonywać pracę, do której została skonstruowana Administrator bazy musi zarezerwować sobie czas od 22:00 do 23:00 wieczorem, aby sporządzać zapasowe kopie danych Łatwość w użyciu Wymaganie to służy określeniu stopnia, w jakim przeszkoleni użytkownicy mogą korzystać z systemu Aplikacja zawiera moduł Pomoc online, który obejmuje 90% jej opcji Łatwość w nauce Wymaganie to jest miarą łatwości oraz czasu, w jakim użytkownicy są w stanie poznać system Po jednodniowym treningu użytkownicy powinni być w wystarczającym stopniu zaznajomieni z aplikacją, aby rozpocząć z nią pracę Architektura Po przeanalizowaniu zapisanych wymagań klienta możesz wybrać odpowiednią architekturę, technologie i narzędzia rozwoju. Czy aplikacja klienta powinna być oparta na Excelu, Accesie czy VB? A może, za pomocą ASP i XML, powinna korzystać z sieci Web? Czy można zastosować konstrukcję dwuwarstwową, czy może n-warstwowa byłaby lepsza? Czy motorem bazy danych będzie Jet-MDB, SQL-MSDE, SQL Server czy Oracle? Oto kilka ważnych pytań, z których każde będzie miało duży wpływ na produkt końcowy. Dopiero, gdy na nie odpowiesz, będziesz mógł właściwie określić budżet i harmonogram prac. Planowanie rozwoju Po podjęciu decyzji dotyczących wymagań i architektury powinieneś zastanowić się nad najlepszym sposobem skonstruowania aplikacji. Czy wszystkie opcje i zestawy funkcji powinny być umieszczone w wersji 1.0, czy może powinieneś część z nich umieścić dopiero w następnych wersjach? Niezależnie od tego, którą z metod wybierzesz, nim przejdziesz dalej, powinieneś zastanowić się nad budżetem i harmonogramem. Być może już sporządziłeś wstępny plan projektu, który został zaakceptowany i dzięki temu dotarłeś do tej fazy projektu. Ta wstępna wersja opierała się na przewidywanych wymaganiach i zakresie aplikacji, a także sporządzonym z dużym przybliżeniem budżecie i harmonogramie. Jeśli posiadasz taki wstępny plan, teraz nadeszła chwila, by go skorygować. Jeśli taki plan jeszcze nie istnieje, teraz powinieneś go napisać. Po zakończeniu fazy Wymagania masz już wystarczająco dużo informacji, by sporządzić listę zadań, listę zasobów, harmonogram i budżet. Programiści powinni posiadać stałą kontrolę nad czasem. Najlepszym sposobem na wykształcenie w sobie umiejętności przewidywania jest porównywanie własnych prognoz z czasem, który jest faktycznie niezbędny do wykonania danej czynności. Strategia dostarczania Staraj się unikać umieszczania każdego pomysłu i przydatnych opcji w jednej, olbrzymiej edycji. Prawie zawsze lepiej jest zaplanować kilka dodatkowych wersji. Wróćmy do przykładu ze sprawozdaniem o kosztach. Podczas spotkań programistów z decydentami dyskutowano na temat możliwego zakresu aplikacji, harmonogramu prac i budżetu. Zgodzono się, iż wersja 1.0 powinna skoncentrować się na automatyzacji tworzenia, zatwierdzania, podziału i kontroli raportów o kosztach. Kolejna wersja, z numerem 2.0, zautomatyzuje tworzenie, zatwierdzanie, podział i kontrolę procesu rozliczania zaliczek na poczet delegacji. Rysunek 2.3 przedstawia kolejne etapy rozwoju aplikacji oraz przykłady możliwych edycji. Na rysunku 2.4 znajduje się poprawiony diagram procesu, pokazujący, która z planowanych w obecnej strategii dostarczania dwóch wersji obejmuje poszczególne etapy procesu. Rysunek 2.3. Przykład strategii dostarczania Rysunek 2.4. Przykład diagramu procesu dotyczącego sprawozdania o kosztach i delegacjach, uwzględniający strategię dostarczania Styl Profesjonalne aplikacje zawsze charakteryzują się jednolitym wyglądem i sposobem działania. Jeśli do zamykania niektórych formularzy używamy przycisku Anuluj, a innych Zamknij, użytkownicy szybko się pogubią, co spowoduje wzrost kosztów szkolenia i pomocy. Jeśli jeden z programistów lubi, gdy każde pole w formularzu umieszczone jest w osobnym, wklęsłym okienku, a wyświetlane dane są zawsze pogrubione, podczas gdy inny projektuje formularze z pogrubionymi etykietami i płaskimi polami tekstowymi, aplikacja będzie sprawiała wrażenie niespójnej. Decyzje co do tych cech podejmij na początku procesu rozwoju i spraw, by wszyscy programiści się z nimi zapoznali, zanim przejmą własne rozwiązania. Oto kilka typów elementów stylu, które powinieneś określić w swoim standardzie: ? Układ formularza (na przykład: rozmieszczenie formantów, rozmiar i proporcje formularza). ? Grupowanie pól (na przykład: wklęsłe ramki czy proste linie) ? Określenie dla pól i etykiet rodzaju, koloru, rozmiaru i stylu czcionki (pogrubienie/kursywa) ? Nazwy oraz sposoby reagowania przycisków (na przykład: Anuluj, Zamknij czy Zakończ?) ? Wskazanie użytkownikowi, czy formularze są przeznaczone tylko do odczytu, czy też można je edytować. ? Sposób komunikacji z użytkownikiem (na przykład: zwięzły bądź rozwlekły). Zamiast tracić czas na pisanie oficjalnego dokumentu, utwórz po prostu bazę danych z zestawem formularzy i raportów zawierającym przykłady najczęściej używanych formantów. Plik ten może być rozwijającym się przykładem preferowanych przez Ciebie stylów interfejsu użytkownika. Jeszcze lepiej będzie, jeśli oprócz formularzy zamieścisz tam także kod opisujący poruszanie się po formularzach i inne powszechnie używane zestawy funkcji. Formularze te posłużą jako standardowe szablony dla twoich produktów. Standardy Bez standaryzacji pracy programistów aplikacje staną się bardzo kłopotliwe w obsłudze i użytkowaniu. Zasada 1: Standardy dużo ulepszają. Zasada 2: Standardy same w sobie nic nie ulepszają. Podstawowym celem standaryzacji jest ujednolicenie efektów pracy członków zespołu programistów. To, że wszyscy piszą w „dobrym” stylu, jest sprawą drugorzędną. Nie trać czasu na spory, co jest w danym momencie najlepsze – po prostu wybierz dobrą metodę, przekonaj do niej innych i trzymaj się jej. Najbardziej powszechne typy standardów to nazewnictwo i kodowanie. Standardy te znacznie ułatwiają czytanie i przeglądanie kodu programu, a także upraszczają późniejsze czynności serwisowe. Standardy nazewnictwa Poniższy przykład korzysta z przyrostkowego standardu nazewnictwa i czynności wykonywane przez programistę są oczywiste. DblLodgingTotal = Double(intNights) * dblRate Natomiast kolejny przykład nie jest już taki oczywisty. x = Text7 * Text12 Oto kluczowe elementy większości standardów nazewnictwa: ? przedrostki obiektowe (na przykład: txt, cbo, lst...); ? przedrostki typów danych (na przykład: sgl, int, str...); ? typowe nazwy baz (na przykład: użycie Acct lub Account); ? typowe skrótowce (na przykład: stat = status). Standardy kodowania Oto przykłady elementów, które możesz chcieć określić w standardach kodowania: ? komentarze nagłówków; ? komentarze w kodzie; ? wcięcia; ? rozmiar podprocedur i funkcji (na przykład: maksymalnie 60 wierszy); ? użycie instrukcji Option Explicit. Istnieją określone standardy nazewnictwa dotyczące rozwoju aplikacji w środowiskach Access/VBA/Office/VB. Dwa najpopularniejsze to konwencje nazewnictwa Reddicka i Leszynskiego. Zaletą korzystania z tych konwencji jest to, że nowi programiści zatrudnieni przez Twoją firmę mogą już je znać. Poza tym, konwencje te są używane w fachowej prasie, książkach oraz w materiałach szkoleniowych. Wybierz jedną z nich i konsekwentnie się jej trzymaj. Konstrukcja Aby podnieść wydajność zespołu w fazie Konstrukcja możesz stosować kilka technik. W tej części omówimy zagadnienia związane z podziałem zadań między programistami oraz kontrolować projekt i proces jego wdrażania. Przekonamy Cię także do dokładnego przetestowania aplikacji i znalezienia wszystkich dotychczas popełnionych błędów. Dziel i rządź: działania w fazie Konstrukcja Istnieje wiele podejść do fazy Konstrukcja. Możesz zacząć od wdrożenia najtrudniejszych i najbardziej niepewnych części aplikacji lub rozpocząć od tych najłatwiejszych części. Możesz także zacząć od formularzy i zakończyć na raportach. Mimo iż wszystkie te podejścia są prawidłowe, wielu programistów osiągnęło sukces, zaczynając od stworzenia solidnych podstaw i na nich budując resztę aplikacji. Podstawy najczęściej składają się z projektu tabel, nakreślenia głównych formularzy i często używanych modułów i funkcji. Działanie takie ma na celu stworzenie działającego rdzenia, stanowiącego podstawę działania każdego z programistów. Jeśli chodzi o formularze, dobrze jest poświęcić trochę czasu na stworzenie jednego lub dwóch, które później posłużą jako szablony dla następnych. Nadeszła odpowiednia chwila, by zainwestować w tworzenie komponentów, które będziesz mógł wykorzystywać wielokrotnie. Wysiłek włożony w zaprojektowanie i testowanie tych elementów zacznie zwracać się z każdym ich użyciem. Ważne jest, aby podczas tworzenia podstaw aplikacji zespół programistów ściśle ze sobą współpracował. Wówczas to zapadają najważniejsze decyzje, a także definiowane są interfejsy. Po stworzeniu tych podstaw dużo łatwiej jest programistom pracować osobno lub podzielić się na mniejsze grupy. Istnieją dwa wydajne sposoby dzielenia procesu wdrożenia między grupy: według obiektów Accessa lub według obiektów aplikacji. Gdy dzielimy zadania według obiektów Accessa, jeden z zespołów koncentruje się na formularzach, inny na raportach, a może zaistnieć potrzeba utworzenia trzeciego zespołu, który zajmie się kodowaniem reguł handlowych i dostarczeniu procedur wspomagających. Jeśli używasz architektury zorientowanej na obiekty, możesz rozdzielić zadania według obiektów aplikacji. Przykładowo, jeden z zespołów zająłby się tworzeniem obiektów Sprawozdania o kosztach (moduły, tabele, formularze, raporty), a inny tworzeniem obiektów związanych z Zatwierdzaniem (moduły, tabele, formularze, raporty). Rysunek 2.5 przedstawia pięć etapów postępowania wszystkich zespołów w fazie Konstrukcja. Rysunek 2.5. Etapy fazy Konstrukcja Ten sam sposób postępowania wykorzystywany jest na różnych poziomach procesu rozwoju. Na najwyższym z nich diagram ten opisuje powstawanie całej aplikacji na przestrzeni kilku miesięcy, począwszy od sporządzenia szczegółowego projektu, aż do ostatecznych testów aplikacji. Na dużo niższym poziomie ten sam diagram mógłby opisywać, jak jeden programista spędza popołudnie na opracowywaniu jednej z zamówionych opcji. Podczas trwania fazy Konstrukcja wypuszcza się zazwyczaj kilka wersji programu. Najczęściej są to: prototyp sprawdzający funkcjonalność graficznego interfejsu użytkownika (GUI); kilka wersji alfa, dzięki którym otrzymujemy wstępne uwagi od użytkowników; jedna lub dwie wersje beta, umożliwiające użytkownikom przetestowanie aplikacji w rzeczywistych warunkach; i wreszcie oficjalna wersja 1.0, dostarczana wszystkim użytkownikom. Edycje i kompilacje Wraz ze wzrostem złożoności aplikacji i projektu ważności nabiera śledzenie wszystkich wypuszczanych wersji aplikacji. Co pewien czas twórz (patrz następna wskazówka) edycję aplikacji zawierającą ostatnie poprawki i zmiany dokonane przez wszystkich programistów. Robiąc to codziennie lub co dwa dni, każdy z programistów ma dostęp do najnowszych poprawek. W tabeli 2.2 znajdziesz przykłady edycji, które mogą powstać podczas rozwoju aplikacji. Kompilacja Kompilacja jest nową wersją aplikacji. Najczęściej zawiera ona umieszczoną w systemie klienta bazę danych wraz ze wszystkimi powiązanymi z nią plikami typu DLL i EXE oraz znajdujące się na serwerze pliki danych. Dla wewnętrznych potrzeb zespołu programistów podczas rozwoju aplikacji powstanie wiele kompilacji. W rzeczywistości tylko kilka z nich trafia do użytkowników. Przykład w tabeli 2.2 przedstawia projekt, podczas którego powstało 178 kompilacji, ale tylko szesnaście edycji (definicja edycji znajduje się poniżej). Edycja Edycja to kompilacja, która zostaje wypuszczona poza zespół programistów. Zazwyczaj jest ono przekazywane jednemu lub więcej użytkownikom końcowym. Nie przejmuj się za bardzo ilością kompilacji. Ich duża ilość nie jest oznaką słabości procesu rozwoju, lecz ostrożności, z jaką go przeprowadzasz. Tabela 2.2. Przykłady edycji Edycja Kompilacja Prototyp 1 Prototyp 2 V1.0 Alfa 1 12 V1.0 Alfa 2 27 V1.0 Beta 1 42 V1.0 Beta 2 56 Wersja 1.0 EK1 88 Wersja 1.0 EK2 89 Wersja 1.0 89 Wersja 1.1 EK1 93 Wersja 1.1 93 Wersja 1.2 EK1 97 Wersja 1.2 EK2 98 Wersja 1.2 98 Wersja 2.0 135 Wersja 3.0 178 Tworzenie nowej kompilacji (rysunek 2.6) należy rozpocząć od zebrania w jedną całość zmian i dodatków od wszystkich programistów. Czasami ich integracja jest równie prosta jak import nowego raportu do interfejsu bazy danych. Częściej jednak dodanie nowego formularza lub modułu pociąga za sobą konieczność dokonania zmian w jednym lub więcej formularzach, aby uwzględnić w nich nowy zestaw funkcji. Może się okazać, że dwóch programistów będzie musiało połączyć swe siły i zintegrować te zmiany. Po wkomponowaniu w kompilację wszystkich dodatków i zmian możesz zaktualizować nazwę edycji/kompilacji wyświetlaną przez aplikację. Rysunek 2.6. Tworzenie kompilacji Pamiętaj o wstawieniu aktualnej nazwy edycji i kompilacji w startowym formularzu aplikacji oraz formularzu „O programie” otwieranym z poziomu menu Pomoc. To ułatwia określenie, w której wersji znaleziono błąd. Przykładowo: „Wersja 1.0 edycja 89 – 2/24/2000”. To także idealny moment na wykonanie kopii zapasowej całej kompilacji. Kopia ta powinna zawierać zarówno bazę danych, jak i wszystkie pliki, które uległy modyfikacji przy przejściu z jednej kompilacji do drugiej. Ponieważ w projekt włożono już znaczące zasoby i czas, warto sporządzić tę kopię na osobnym nośniku. Aby upewnić się, że poszczególne części właściwie ze sobą współpracują, po stworzeniu nowej kompilacji każdorazowo powinieneś przeprowadzać testy integralności. Po stwierdzeniu, iż nowa kompilacja działa bez zarzutu, powinieneś dostarczyć je każdemu członkowi zespołu. Umieść kopię aplikacji w ogólnodostępnym katalogu, by każdy z programistów i testerów miał do niego dostęp. Jeśli to możliwe, skorzystaj z funkcji narzędzia służącego do kontroli wersji, takiego jak Microsoft Visual SourceSafe. Dzięki temu będziesz mógł budować i śledzić tworzone kompilacje, a także ograniczyć problemy powstające na skutek zmian dokonywanych przez kilku programistów. Jeśli nie korzystasz z Visual SourceSafe, procedury archiwizacyjne stają się jeszcze ważniejsze. Niektóre kompilacje powstają na różnych etapach procesu rozwoju (patrz przykłady w tabeli 2.2 i na rysunku 2.8). Podczas fazy koncepcyjnej lub zbierania wymagań dobrze jest stworzyć jeden lub kilka prototypów, które pozwolą użytkownikom ocenić wygląd proponowanego GUI. Później, gdy kilka z podstawowych opcji już działa, bardzo przydatnym może okazać się przekazanie jednemu lub dwa użytkownikom edycji alfa. Dzięki temu będziesz znał ich opinię, co może pozwolić Ci znacznie zmniejszyć ryzyko niepowodzenia. Gdy aplikacja jest już prawie gotowa, dostarczenie użytkownikom do testów wersji beta znacznie podwyższy jakość produktu końcowego. Większość z tych edycji powstaje dla każdej z głównych wersji (duże zmiany) i mniejszych poprawek (małe zmiany). Przed wypuszczeniem ostatecznej wersji warto też oddać użytkownikom do testów jedną lub kilka edycji-kandydatek (EK1, EK2 i tak dalej). Aby utworzyć edycję, weź prawidłowo działającą kompilację i przygotuj pakiet instalacyjny. Czynność ta może być tak prosta jak spakowanie interfejsu bazy danych albo tak skomplikowana jak stworzenie profesjonalnego skryptu instalacyjnego przy użyciu zawartego w Office 2000 Developer’s Edition narzędzia instalacyjnego. W obu przypadkach, edycja powinna być przetestowana na kilku komputerach, aby upewnić się, że działa bez zarzutu (rysunek 2.7). Gdy produkt z pozytywnym wynikiem przejdzie fazę testów, przekaż go do zainstalowania użytkownikom. Do każdej wersji dołącz „Informacje o edycji”. Wylicz w nich nowe opcje, zmiany i znane problemy. Nawet jeśli użytkownik nigdy ich nie przeczyta, przydają się one programistom, gdyż czytając je, wiedzą, co w danej edycji zostało zmienione. Nie zapomnij o aktualizacji dokumentacji użytkownika, za każdym razem, gdy dokonujesz zmian w aplikacji. Nieaktualna dokumentacja jest gorsza niż całkowity jej brak. Rysunek 2.7. Tworzenie edycji W czasie trwania projektu utworzonych zostanie wiele edycji i kompilacji. Na rysunku 2.8 przedstawiono przykład cyklu, w którym tworzone są edycje i kompilacje. Każda kompilacja daje programistom, testerom, a czasami nawet użytkownikom okazję do przetestowania aplikacji i podzielenia się z resztą zespołu swoimi uwagami i spostrzeżeniami. Nazywane są one często usterkami lub problemami. W zależności od ich ważności w stosunku do kontynuacji rozwoju aplikacji poprawienie ich następuje już w następnej kompilacji lub też odkładane jest na później. Rysunek 2.8. Przykład cyklu kompilacji i edycji Szczegółowy projekt Mimo iż w większości opcji i zadań sposób ich implementacji w aplikacji jest oczywisty, zdarza się (w pięciu do dwudziestu procent przypadków), że wymaga to chwili zastanowienia. Do typowych przykładów należą moduły, formularze nawigacyjne, skomplikowane algorytmy i rzadkie techniki automatyzacyjne. Projekt takich opcji lub zadań powinien być w jakiś sposób udokumentowany. Pozostaw po swoich decyzjach i sposobie ich uwzględnienia w projekcie jakiś ślad. Może on przydać się tobie lub komuś innemu, gdy nadejdzie potrzeba dokonania pewnych zmian. Zachowaj dokumentację dotyczącą projektu do czasu, gdy wyjaśnione zostaną wszelkie wątpliwości. Doskonałym sposobem na opisanie niestandardowych algorytmów jest umieszczenie w procedurze lub funkcji komentarzy w pseudokodzie. Pseudokod jest to uproszczony kod VBA, dołączony jako komentarz opisujący implementowany w danym miejscu kodu proces. Dokładna składnia nie jest ważna. Opisujesz jedynie algorytm użyty w VBA. Poniższy przykład przedstawia użycie pseudokodu w nagłówku procedury. Public Sub ProcessAllUpdates() ' Comments : Get the updated mail from MAPI Inbox, ' unattatch it and update the current database. ' Parameters : ' Returns : ' Created : Tuesday, July 27, 1999 11:44 PM by Joe Developer ' Pseudo Code : ' -------------------------------------------------------------- ' Sub ProcessUpdates() ' UpdateCount = 0 ' UnattatchAllUpdates() ' Open a recordset from tblDownloadReceivedResults ' For each in Recordset ' ProcessOneUpdate() ' If succesful Then ' Delete Update file ' Increment(UpdateCount) ' Next ' -------------------------------------------------------------- Kontrola projektu Kontrola projektu polega na skonsultowaniu problemów wynikłych podczas tworzenia projektu oraz sposobów ich rozwiązania z osobami trzecimi. Konsultacja ta może być całkiem nieformalna, ale równie dobrze może przybrać formę oficjalnej prezentacji podczas zebrania członków zespołu. Często zdarza się, że podczas opisywania projektu innym osobom zauważasz nowe problemy lub lepsze rozwiązania. Inny programista często znajduje to, co Ty przeoczyłeś. To doskonały moment, by wykryć błędy w aplikacji, zanim rozpoczniesz czasochłonne kodowanie i testowanie. Tworzenie aplikacji Tworzenie aplikacji jest tym etapem procesu rozwoju, który klientom, użytkownikom i niedoświadczonym programistom kojarzy się z procesem pisania programu. Podczas tej fazy powstają formularze i raporty oraz pisany jest kod programu. Większość rozdziałów tej książki obejmuje zagadnienia związane z tą fazą procesu rozwoju. Kontrola aplikacji Kontrola aplikacji (lub kodu programu) przypomina kontrolę projektu, z tą różnicą, że dotyczy efektów jego wdrożenia. Zazwyczaj kontrola tworzonych formularzy, raportów, kwerend, a także kodu programu niesie ze sobą wiele korzyści. Podobnie jak to miało miejsce w przypadku kontroli projektu, przez samo opisywanie tego, co zrobiłeś i jak to działa, zauważasz elementy, które wcześniej przeoczyłeś. Osoba trzecia, patrząc na Twoją pracę, może zauważyć coś, co pominąłeś. Ty lub osoba, z którą konsultujesz aplikację, możecie odnaleźć błędy powstałe w trakcie jej tworzenia, w jej projekcie, architekturze lub wymaganiach klienta. Pamiętaj, że im wcześniej błąd jest odnaleziony, tym mniej kosztuje jego naprawienie. Kontrole kodu programu przynoszą dodatkową korzyść w postaci podnoszenia umiejętności programistów. Aby to osiągnąć, poproś doświadczonych programistów, by kontrolę kodu programu zlecali nowym lub mniej doświadczonym członkom zespołu. Inną korzyścią jest poznanie przez programistów części aplikacji pisanych przez ich kolegów. Konsekwentne używanie standardów nazewnictwa i kodowania znacznie ułatwia i skraca proces kontroli kodu programu. Pozwala także uniknąć dyskusji na temat przewagi jednych stylów nad innymi. Jeśli jesteś samotnym programistą (chodzi nam oczywiście o to, że nie pracujesz w zespole), znajdź innego programistę i dokonujcie wzajemnej kontroli kodu. Poświęcony temu czas szybko się wam zwróci. Bardzo pomocne mogą być tu grupy użytkowników. Testowanie Testowanie w procesie rozwoju odbywa się na kilku poziomach: jednostki, aplikacji, konfiguracji i instalacji. Testowanie modułu Przed rozpoczęciem tworzenia opcji lub obiektu zastanów się, jak zamierzasz je testować. Po utworzeniu danego elementu przeprowadź zaplanowane testy, aby sprawdzić, czy jego działanie jest zgodne z Twoimi intencjami oraz czy można ten element dołączyć do reszty aplikacji. Z doświadczenia wiemy, iż 20% czasu tworzenia aplikacji powinno się poświęcić na testowanie wszystkich opcji i obiektów. Przykładowo, jeśli poświęciłeś siedem godzin na opracowanie algorytmu i trzy godziny na napisanie go i usunięcie błędów, to można założyć, że testowanie go powinno zabrać Ci około dwóch godzin. Jeśli testujesz podprogram, funkcję lub moduł, przetestuj wszystkie możliwe parametry wejściowe, poprzez wprowadzenie zarówno oczekiwanych, jak i nieoczekiwanych wartości. Podczas testowania nowego formularza upewnij się, że sprawdziłeś, czy wszystkie formanty działają poprawnie. Przede wszystkim sprawdź, czy prawidłowo funkcjonują: kontrola poprawności wprowadzanych danych, zablokowane pola, kolejność klawisza Tab, wstawianie nowych rekordów, jednolitość stylów i poruszanie się po formularzu. Testowanie aplikacji Testowania aplikacji (lub systemu) dokonuje się na całej aplikacji po umieszczeniu w niej wszystkich opcji. Istnieje kilka przyczyn uzasadniających wykonywanie tego typu testów. Najważniejszą z nich jest stwierdzenie, czy aplikacja uwzględnia wszystkie wymagania zgłoszone przez klienta. Drugą z przyczyn jest określenie, w jakim stopniu aplikacja jest gotowa do wypuszczenia jej na rynek. Oto przykłady testów, które powinieneś wykonać: ? Przetestuj zachowanie aplikacji, gdy tabele są puste. ? Sprawdź różne rozdzielczości ekranu. ? Przetestuj oba ustawienia rozmiaru czcionki we Właściwościach ekranu systemu Windows (Małe czcionki i Duże czcionki). ? Zastosuj kilka różnych zestawów kolorów we Właściwościach ekranu systemu Windows. ? Sprawdź, jak wyglądają wydruki na kilku różnych drukarkach (uwzględnij zwłaszcza markę i model drukarki posiadanej przez klienta). ? Przetestuj aplikację zarówno z włączoną jak i wyłączoną opcją Autoukrywanie paska Narzędzi systemu Windows. ? Sprawdź, czy pomoc „Co to jest?”, etykietki narzędzi i pasek stanu odpowiadają właściwym polom. ? Sprawdź kolejność klawisza Tab na każdym formularzu. ? Upewnij się, że klawisze skrótu na każdym formularzu są identyczne. ? Przetestuj na każdym formularzu działanie klawiszy domyślnych (Enter i Esc). ? Sprawdź jednolitość stylów na każdym formularzu i raporcie. Testowanie instalacji i konfiguracji W rzeczywistości rzadko się zdarza, by komputery użytkowników były takie same jak komputery programistów. Używają one innego oprogramowania, ilość pamięci jest różna, często korzystają z dziwnych drukarek i jeszcze dziwniejszych kart graficznych. Innymi słowy, komputery użytkowników czynią życie programistów ciekawszym. Ta różnorodność konfiguracji ma duży wpływ na łatwość instalacji aplikacji, a także na jej późniejsze działanie. Jeśli to możliwe, postaraj się przetestować aplikację w najgorszym środowisku, jakie możesz sobie wyobrazić. W przypadku większych projektów rozważ wykorzystanie do tego celu wyspecjalizowanej firmy. Oferują one laboratoria przepełnione zarówno nowym, jak i starszym sprzętem oraz oprogramowaniem. Instalację i sprawdzenie funkcjonowania aplikacji przeprowadź zarówno na „czystym”, jak i na „brudnym” komputerze. Przez „czysty” komputer rozumiemy taki, gdzie na niedawno sformatowanym dysku zainstalowano tylko system operacyjny i niezbędne oprogramowanie (tak jak na fabrycznie nowym komputerze). „Brudny” komputer to taki, na którym w dłuższym okresie czasu instalowano wiele wersji różnych aplikacji. Testowanie aplikacji na obu rodzajach komputerów pozwoli odnaleźć nieoczekiwane problemy związane z plikami typu DLL, ustawieniami rejestru, szablonami i innymi wspomagającymi plikami. Do szybkiego odtwarzania różnych konfiguracji komputera warto użyć oprogramowania służącego do sporządzania obrazu dysku. Nie oczekuj, że przeprowadzenie testów pozwoli Ci odkryć wszystkie błędy. Większość aplikacji jest zbyt skomplikowana, aby można było przetestować każdą możliwą kombinację wartości danych i ścieżek wykonywania. Dlatego właśnie tak ważne są wcześniejsze działania, czyli określenie wymagań, planowanie oraz kontrole projektu i aplikacji. Stanowią one pierwszy i jednocześnie najlepszy sposób na wyeliminowanie błędów. Dużo łatwiej jest zapobiegać usterkom przez dokładne projektowanie niż odnajdywać je i usuwać później. Odnajdywanie usterek Przez usterkę rozumiemy każdy błąd, niedociągnięcie bądź problem związany z funkcjonowaniem aplikacji. Może to być błąd w dokumencie, narzędziu bądź we wdrożeniu aplikacji. Usterki mogą być odnajdywane na każdym etapie procesu rozwoju i wszystkie powinny być zgłaszane. Każda z poniższych czynności może ukazać istniejące usterki: ? Kontrola projektu i aplikacji – usterki odkryte w fazie kontroli to zarówno niezgodność z przyjętymi standardami jak i usterki w samym projekcie. ? Kontrola dokumentów – podczas kontroli dokumentów można odkryć wiele potencjalnych usterek. Może brakować dokumentu zawierającego wymagania lub mogą być one niewłaściwie zdefiniowane. Dokumentacja projektu może nie obejmować wszystkich wymagań lub po prostu zawierać błędy. ? Testowanie – najczęstszymi usterkami wykrywanymi w tej fazie są błędy w kodzie programu. Można wówczas również odkryć błędy w dokumentacji, gdyż to właśnie na jej podstawie testy powinny się odbywać. ? Obsługa klienta – podczas testowania wersji beta lub po dostarczeniu aplikacji do klienta błędy stwierdzone przez użytkowników zostaną przekazane bezpośrednio do programisty lub personelu zajmującego się obsługą klientów. System zbierania informacji o błędach powinien także dawać użytkownikom możliwość zgłaszania pomysłów ulepszenia aplikacji. ? Obsługa błędów – jeśli używasz automatycznego zgłaszania błędów, które opisaliśmy w rozdziale 13. „Profesjonalna obsługa błędów”, informacje o błędach mogą być przesyłane pocztą elektroniczną lub zapisywane w specjalnym pliku na komputerze klienta. Niezależnie od tego, z jakiego źródła pochodzi informacja o błędzie oraz kto ją zgłasza, musi ona być udokumentowana. Wszystkie informacje o błędach przechowuj w jednym miejscu. Informacje umieszczone na różnych kartkach czy w e-mailach możesz zgubić lub zwyczajnie o nich zapomnieć. Możesz używać dostępnego w sprzedaży narzędzia służącego do śledzenia błędów, stworzyć osobną bazę danych w Accessie lub zapisywać usterki na komputerze przenośnym. Jakkolwiek przechowujesz informacje o błędach, będziesz potrzebował procesu zapewniającego, że każda usterka jest analizowana. Zauważ, że „analizowana” nie musi koniecznie oznaczać „naprawiana”. Może się zdarzyć, że w zależności od tego jak poważny jest błąd i jak często występuje, zdecydujesz się go nie naprawiać. Każda usterka powinna przejść ten sam proces, począwszy od jej stwierdzenia aż do rozwiązania. 1. Zaraz po odkryciu błędu informacje o nim wprowadź do systemu kontroli błędów. Tabela 2.3 zawiera listę informacji, które według nas powinieneś zbierać. W tabelach od 2.4 do 2.8 znajdziesz dalszy opis informacji o usterkach. 2. Zespół programistów powinien co pewien czas przejrzeć nierozpatrzone usterki i określić ważność każdej z nich. Decyzja ta powinna być oparta na wadze, częstości występowania i powtarzalności każdej usterki. Następnym krokiem jest przydzielenie zadania rozwiązania problemu jednemu z programistów. 3. Programista naprawia usterkę lub stwierdza, że nie zaszła taka konieczność. Do niego należy także uaktualnienie opisu i statusu rozwiązania problemu. Jeśli usterka została zlikwidowana, status rozwiązania problemu zostanie zmieniony na „poprawiono”. 4. Jeśli to możliwe, inny członek zespołu sprawdza wszystkie poprawione błędy. Wówczas status rozwiązania problemu zmieniany jest na „sprawdzono”. Tabela 2.3. Informacje o usterkach Pole danych Opis Unikatowy identyfikator Można używać kolejnych liczb. Jeśli informacje o usterkach wprowadza kilka osób, upewnij się, że liczby te się nie powtarzają Opis usterki Opisz wygląd potencjalnego błędu, łącznie z kodami błędów i sposobem działania, który do jego wystąpienia prowadzi Znalezione przez Nazwisko osoby zgłaszającej usterkę Kiedy znaleziono Data i godzina odkrycia Oczekiwane rezultaty Co miało się stać? Tabela 2.3. Informacje o usterkach (ciąg dalszy) Pole danych Opis Gdzie odnaleziono Sporządź listę dokumentów i elementów programu, których zgłaszane usterki mogą dotyczyć (na przykład: dokument zawierający informacje o wymaganiach, dokumentacja dotycząca architektury, nazwa formularza, nazwa raportu, nazwa modułu) Wersja Określ wersję dokumentu lub bazy danych (na przykład: Beta 2.1, kompilacja 36, dokument dotyczący wymagań z dnia 29/06/2000 i tak dalej) Oprogramowanie i konfiguracja komputera Sporządź listę istotnych informacji dotyczących konfiguracji komputera, jak rozdzielczość ekranu, ilość wyświetlanych kolorów, ilość pamięci, wolna przestrzeń dyskowa, system operacyjny, jednocześnie używane oprogramowanie i tak dalej Waga Jak poważny jest wykryty problem? Patrz tabela 2.4 Częstotliwość Jak często błąd występuje? Patrz tabela 2.5 Powtarzalność Jak łatwo doprowadzić do ponownego wystąpienia błędu? Patrz tabela 2.6 Ważność Jak ważne jest naprawienie tej usterki? Patrz tabela 2.7 Osoba odpowiedzialna Który z programistów zajmie się rozwiązaniem tego problemu? Status rozwiązania problemu Jaki jest status usterki? Patrz tabela 2.8 Opis rozwiązania problemu W jaki sposób „poprawiono”? Dlaczego „odłożono na później” lub „zignorowano”? Tabela 2.4. Waga usterki Waga Kryteria Krytyczna Niepełny zestaw funkcji bądź utrata danych Poważna Opcja nie działa tak jak zaplanowano; zmniejszenie użyteczności. Przeciętna Powoduje, iż aplikacja zawiesza się, lecz nie w sposób krytyczny; nie następuje utrata danych Niska Kosmetyczny problem lub prośba o ulepszenie danej opcji Tabela 2.5. Częstotliwość występowania Częstotliwość Kryteria Powszechna Użytkownik podczas normalnego korzystania z aplikacji z łatwością zauważy usterkę, co najmniej raz za każdym użyciem. (Na przykład: zamykając główny formularz) Tabela 2.5. Częstotliwość występowania (ciąg dalszy) Częstotliwość Kryteria Okazjonalna Jest mało prawdopodobne, by użytkownik trafiał na usterkę za każdym razem, gdy używa produktu, lecz prawdopodobnie kiedyś ją zauważy. (Na przykład: usterka występuje tylko podczas drukowania dwustronicowej faktury) Rzadka Bardzo mała część użytkowników zauważy tę usterkę. (Na przykład: usterka dotyczy tylko określonych kart graficznych) Tabela 2.6. Powtarzalność usterki Powtarzalność Kryteria Zawsze Usterka powtarza się zawsze. Nieciągła Usterka zwykle występuje, ale nie zawsze. Raz Usterkę zaobserwowano raz, nie przeprowadzono dalszych testów powtarzalności. Niepowtarzalna Usterkę zaobserwowano raz i nie udało jej się powtórzyć. Tabela 2.7. Ważność naprawienia usterki Ważność Opis Krytyczna Musi zostać naprawiona Wysoka Powinna zostać naprawiona, jeśli to tylko możliwe Przeciętna Naprawić, jeśli starczy czasu Przełożyć na później Nie trzeba naprawiać w tym momencie Tabela 2.8. Rozwiązanie problemu Rozwiązanie Opis Nie rozwiązano Problem nowy i jeszcze nie analizowany Zignorowano Element działa tak, jak zaplanowano Odłożono na później Problem nie zostanie rozwiązany w tym momencie Poprawiono Problem został rozwiązany i czeka na sprawdzenie Sprawdzono Naprawiony element został przetestowany i usterka jest usunięta Możesz usprawnić proces rozwoju, odnajdując przyczyny leżące u podstaw powstawania usterek. Określając, jak i gdzie powstała usterka, możesz znaleźć sposób na uniknięcie tego w przyszłości. Najczęstsze z takich przyczyn to: błędy w projektowaniu i kodowaniu, braki w wymaganiach lub niejednoznaczne ich zdefiniowanie, a także niewystarczające przeszkolenie programistów i klientów. Kontrola wersji Istnieje wiele przyczyn, dla których powinieneś w jakiś sposób kontrolować wersje aplikacji w procesie rozwoju. Za każdym razem, gdy zespół składa się z więcej niż jednego programisty, pojawia się kilka przeszkód. Początkowo sprawowanie kontroli nad wersjami wydaje się całkiem proste. Wystarczy przechowywać „główną” bazę danych na serwerze i uważnie przydzielać tworzenie i obsługę obiektów różnym programistom. Łatwe, prawda? Niestety, jak bardzo byś się nie starał temu zapobiec, pewnym jest, że dwóch programistów dokona jednoczesnych zmian w tym samym obiekcie. Być może otworzą dany formularz w tym samym momencie i jeden z nich doda pole, podczas gdy drugi naprawia funkcję. Obydwaj zapiszą zmiany w „głównej” bazie danych. Ten, który to zrobi jako drugi, wygrywa – nadpisze zmiany zapisane przez pierwszego programistę. Przy odrobinie szczęścia, pierwszy programista przetestuje swoją pracę i zauważy, że dokonane przez niego zmiany zniknęły. W innym przypadku, problem zostanie zauważony później. Nie ma nic gorszego niż ponowne wykonywanie tych samych czynności. Jednakże problem ten może zostać rozwiązany przez monitorowanie i kontrolowanie uprawnień do dokonywania zmian obiektów. Inną przyczyną, dla której warto wdrożyć kontrolę wersji, jest możliwość identyfikacji i odtworzenia poprzedniej, działającej wersji aplikacji. Może się zdarzyć, że będziesz chciał sprawdzić, czy dany problem występował we wcześniejszych wersjach. Odtworzenie poprzedniej wersji przydaje się również, gdy zaplanowane zmiany nie odniosły zamierzonych efektów i chcesz je cofnąć. Takie sytuacje zdarzają się niezależnie od rozmiaru zespołu programistów. Istnieje kilka technik i narzędzi, za pomocą których można rozwiązać problemy związane z kontrolą wersji. Prawdopodobnie najlepszym rozwiązaniem jest zakup specjalnie do tego przeznaczonego narzędzia. Najpopularniejszym z nich jest Microsoft Visual SourceSafe, ponieważ program ten jest mocno zintegrowany z Accessem 2000. Możesz także wdrażać różne metody, aby sprostać wyzwaniom związanym z kontrolą wersji aplikacji. Aby rozwiązać kwestię współpracy wielu programistów, możesz sporządzić listę współdzielonych obiektów „głównej” bazy danych. Może to być plik tekstowy lub tabela w Accessie, z której programiści będą mogli sprawdzić, czy dany obiekt jest w danej chwili dostępny oraz wpisać czas pobrania i zwrotu danego obiektu. Jednak, by metoda ta była skuteczna, ustalona procedura musi być bez wyjątków przestrzegana. Innym wyjściem z tej sytuacji jest okresowe sporządzanie kopii zapasowej wszystkich plików powiązanych z aplikacją w postaci nowego podkatalogu lub pliku typu ZIP. Pamiętaj jednak o tym, by podkatalogom i plikom typu ZIP nadawać zrozumiałe nazwy, zawierające kompilację, wersję i datę. Proces ten możesz zautomatyzować z poziomu Accessa 2000. Access różni się od innych narzędzi programistycznych, gdyż zapisuje wszystkie obiekty w jednym pliku typu MDB. Wiele z dostępnych w sprzedaży narzędzi do kontroli wersji jest w stanie śledzić jedynie osobne pliki. Ograniczenie to sprawia, iż każdorazowo zachodzi konieczność pobierania i zwracania całej bazy danych. Dość nieporęczne, prawda? Upewnij się, że narzędzie, którego zakup rozważasz, wspiera Microsoft Accessa, śledząc jego pojedyncze obiekty. Rozdział 3. Projekt bazy danych i normalizacja W tym rozdziale: ? Relacyjne systemy zarządzania bazami danych. ? Teoria projektowania relacyjnego. W trakcie tworzenia aplikacji w Accessie 2000 powinieneś przez cały czas pamiętać, że każda z tworzonych przez Ciebie aplikacji jest bazą danych. Aby tworzyć szybsze i bardziej wydajne aplikacje, musisz poznać i zrozumieć pojęcie normalizacji baz danych – temat tego rozdziału. Mimo iż być może miałeś już okazję zapoznać się z normalizacją baz danych na różnych szkoleniach, powinieneś przyjrzeć się teorii relacyjnej w odniesieniu do Accessa. Relacyjne systemy zarządzania bazami danych (RDBMS) W książkach i czasopismach, jakie czytasz, wielokrotnie możesz spotkać się z pojęciem – relacyjne systemy zarządzania bazami danych (ang. Relational Database Managment Systems – RDBMS). Możesz zapytać, co Access ma wspólnego z modelem RDBMS. Model ten został stworzony w 1970 roku przez pracownika firmy IBM, dr E.F. Codda. Celem ustalonych w modelu RDBMS zasad było uniezależnienie funkcjonowania interfejsów od zmian dokonywanych w modelu danych. Produkty RDBMS używają wspólnych elementów danych, takich jak CustomerID, aby połączyć wiersze w dwóch różnych tabelach, między którymi zachodziła relacja, a także używają tych pól w sprzężeniu. Istnieje 13 zasad, które produkt musi spełnić, aby można go było nazwać Relacyjnym Systemem Zarządzania Bazami Danych. Niektórzy z krytyków Accessa twierdzą, że nie spełnia on tych wymagań, jednakże ja się z tym nie zgadzam i uważam, że nie jest błędem zaliczenie Accessa do grupy projektów RDBMS. Oto 13 zasad relacyjnych i ich zastosowanie w Accessie. Zasady relacyjne dr Codda Access spełnia wszystkie z 13 zasad relacyjnych dr Codda. Tabela 3.1 zawiera nazwę i opis każdej z nich, a także komentarz o zastosowaniu tych zasad w Accessie. Tabela 3.1. Zasady relacyjne dr Codda Zasada dr Codda Nazwa zasady Opis Komentarz dotyczący Accessa Zasada 0. Zasada tworzenia Każdy program typu RDBMS musi być w stanie zarządzać bazami danych jedynie za pomocą swoich zdolności relacyjnych. Jeśli system działa na zasadach operowania danymi rekord-po-rekordzie, nie możemy go nazywać systemem w pełni relacyjnym Access był pierwszą na rynku, działającą w systemie Windows bazą danych, która przestrzegała tej zasady. Access, w przeciwieństwie do niektórych systemów, nie stosuje numeracji rekordów Zasada 1. Informacja Wszystkie dane w relacyjnej bazie przedstawiane są jako wartości w tabelach. Dane nie mogą być przechowywane w żaden inny sposób Access przechowuje dane jako tabele, w aparacie baz danych Jet Zasada 2. Gwarantowany dostęp Poprzez użycie kombinacji wartości klucza podstawowego, nazwy tabeli i nazwy kolumny, musi istnieć dostęp do dowolnej partii danych Access przestrzega tej zasady poprzez użycie kluczy głównych. Jeśli sam nie utworzysz w tabeli klucza głównego, Access zażąda, abyś to zrobił Zasada 3. Brakujące informacje Program musi obsługiwać wartości Null. Wartości te przedstawiają brakujące lub bezużyteczne informacje Access obsługuje wartości Null dla brakujących informacji. Jednocześnie pozwala uniknąć wprowadzania wartości Null poprzez użycie pól wymaganych. Zasada 4. Katalog systemu Opis bazy danych lub „katalog” na poziomie logicznym jako wartości tabelaryczne. Język relacyjny (SQL) powinien móc działać na projekcie bazy danych w taki sam sposób, w jaki działa na danych przechowywanych w strukturze Katalog ten umieszczony jest w aparacie bazy danych Microsoft Jet. Do stworzenia zapytania dotyczącego katalogu systemu możesz użyć obiektu Active Data o nazwie OpenSchema (patrz rozdział 5. „Jet 4.0 – silnik baz danych Microsoft). SQL DDL daje Ci możliwość tworzenia tabel, indeksów itp. Tabela 3.1. Zasady relacyjne dr Codda (ciąg dalszy) Zasada dr Codda Nazwa zasady Opis Komentarz dotyczący Accessa Zasada 5. Kompletny język Program typu RDBMS musi obsługiwać jasno określony język do operowania danymi (SQL), który w pełni obsługuje definiowanie i operowanie danymi, określanie widoku, ograniczenia integralności, ograniczenia transakcyjne i autoryzację Access (Jet) w pełni obsługuje SQL dla operowania danymi, określania widoków (kwerendy wybierające) i ograniczeń integralności (Okno Relacje i komenda UTWÓRZ OGRANICZENIE) Zasada 6. Uaktualnianie widoków Wszystkie widoki mogą być systemowo uaktualnione. W prawdziwym programie typu RDBMS, większość (ale nie wszystkie) widoków może być uaktualniana Access był pierwszą bazą danych, umożliwiającą użycie kwerend aktualizujących Zasada 7. Ustawianie poziomu uaktualnień Program typu RDBMS musi nie tylko potrafić pobierać zestawy danych. Musi także potrafić wstawiać, aktualizować i usuwać dane jako zestaw relacyjny Access spełnia to wymaganie poprzez użycie kwerend funkcjonalnych Zasada 8. Fizyczna niezależność danych Dane i aplikacja muszą być od siebie fizycznie niezależne. Odpowiedni program typu RDBMS lub „optymalizator” powinny móc śledzić fizyczne zmiany w danych. Przykładowo, aplikacje RDBMS nie powinny ulegać modyfikacji na skutek dodania bądź usunięcia z tabeli indeksu Access umożliwia Ci modyfikowanie obiektów bazy danych, bez konieczności dokonywania zmian w reszcie aplikacji. Jet zawiera także logiczny aparat przechowywania Zasada 9. Logiczna niezależność danych Gdy to tylko możliwe, aplikacja powinna być niezależna od zmian dokonywanych w tabelach podstawowych. Przykładowo, gdy tabele są łączone w widok, nie powinny następować zmiany w kodzie Gdy tworzysz w Accessie kwerendę, możesz ją z łatwością połączyć z formularzem lub raportem, jakby to była tabela Zasada 10. Niezależność integralności Integralność danych musi być definiowalna w języku relacyjnym i przechowywana w katalogu. Ograniczenia w integralności danych mogą być wbudowane w aplikację, jednakże podejście to jest obce dla modelu relacyjnego. W modelu relacyjnym integralność powinna być naturalną cechą projektu bazy danych. Mimo iż Microsoft nie umieścił w dokumentacji informacji na temat przechowywania integralności przez aparat Jet, możesz tworzyć zasady integralności poprzez SQL. Jet przechowuje te informacje w projekcie bazy danych jako część katalogu. Tabela 3.1. Zasady relacyjne dr Codda (ciąg dalszy) Zasada dr Codda Nazwa zasady Opis Komentarz dotyczący Accessa Zasada 11. Niezależność podziału Zdolności programu typu RDBMS nie będą ograniczone dzięki umieszczeniu jego komponentów w osobnych bazach danych. Ponieważ silnik Jet przechowuje swoje zasady integralności danych na poziomie aparatu, pozostałe jego komponenty nie mają wpływu na zasady integralności. Zasada 12. Brak podwersji Jeśli program RDBMS posiada język typu „jeden rekord jednocześnie”, język ten nie może być używany do omijania zasad integralności lub ograniczeń języka relacyjnego. Dlatego też nie wystarczy, by zasady relacyjne zarządzały programem typu RDBMS, ale muszą być prawami nadrzędnymi. Access umożliwia Ci użycie obiektów DAO i ADO, aby operować jednym rekordem jednocześnie poprzez aktualizowalne zestawy rekordów. Dzięki tym narzędziom do operowania danymi nie możesz naruszyć zasad integralności. Relacyjne systemy zarządzania bazami danych przeważają w kilku punktach nad innymi systemami, w szczególności w procesie projektowania. Programy typu RDBMS korzystają z teorii projektowania relacyjnego, aby tworzyć własne modele projektowe baz danych. Na tym skupimy się w następnej części tego rozdziału. Teoria projektowania relacyjnego Teoria projektowania relacyjnego, opracowana przez dr Codda w celu rozbudowania zasad relacyjnych, składa się z następujących kategorii: ? Tabele i niepowtarzalność. ? Klucze obce i domeny. ? Relacje. ? Normalizacja danych. ? Zasady integralności. Korzyści z używania modelu relacyjnego Korzystając z teorii projektowania relacyjnego uzyskujesz zalety płynące z lat poszukiwań najlepszego sposobu zarządzania danymi. Niektóre z nich, jakie otrzymasz w wyniku normalizacji bazy danych, to: ? Pewność integralności danych. ? Skuteczność przechowywania danych. ? Możliwość rozwoju bazy danych. ? Zachowanie bazy danych jest przewidywalne, gdyż jest ona zgodna z wielokrotnie przetestowanymi zasadami. ? Ponieważ przestrzegasz tych zasad, inni projektanci baz danych mogą dużo łatwiej zrozumieć Twój projekt. ? Okno Relacje staje się samo w sobie dokumentem. ? Zmiany w schemacie bazy danych są łatwe we wdrożeniu. Tabele i niepowtarzalność Kiedy tworzysz aplikacje bazy danych, każda tabela przedstawia odrębną jednostkę lub proces występujący w rzeczywistym świecie. Będziesz tworzył tabele kontrolujące ludzi, wydarzenia, transakcje finansowe i przedmioty (np. produkty). Zgodnie z teorią relacyjną, musisz przechowywać wszystkie dane w tabelach (zasada 1.) oraz, że tabela składa się z unikatowych wierszy i kolumn (zasada 2.). Sposobem na zapewnienie unikalności każdej z zasad jest ustawienie klucza głównego dla każdego wiersza. Klucz główny to pole lub grupa pól (mówimy wtedy o wielopolowym kluczu głównym), które jest unikatowym identyfikatorem tego wiersza. Klucz główny musi być unikatowy. W przeciwnym bowiem wypadku dochodziłoby do naruszenia zasady 2. Access pozwala Ci uczynić pole kluczem głównym, poprzez nadanie mu wartości Klucz w widoku Projekt tabeli. Access sprawdzi wówczas, czy dane w tym polu są unikatowe i nie występują w nim duplikaty. Czasami, gdy przestrzegamy reguł handlowych, podanie unikatowej wartości dla każdego wiersza może być trudne. Przykładowo, możesz utworzyć przedstawiony na rysunku 3.1 system zarządzający kontaktami. Rysunek 3.1. Przykładowa, nieznormalizowana tabela Podczas projektowania systemu zarządzającego kontaktami, jako klucz możesz wybrać Nazwisko, Telefon lub e-mail (pola takie powszechnie nazywane są „polami-kandydatami”). Ogólna zasada projektowania baz danych głosi, że klucz powinien być jak najprostszy, unikatowy i jak najrzadziej zmieniany. Nazwisko może się zmieniać na skutek zawarcia małżeństwa, rozwodu itp. Numery telefonów i adresy e-mail zmieniają się ciągle. Dobrym kluczem byłby numer PESEL, ale co, gdy dana osoba nie jest obywatelem polskim? W tej sytuacji Access umożliwia Ci utworzenie pola Autonumerowanie, które stanie się polem klucza podstawowego. Autonumerowanie jest samogenerującą się wartością liczbową, która będzie wzrastać z każdym nowym rekordem. Istnieją dwa typy Autonumerowania: ? Wartości całkowite; ? Id replikacji lub GUID (używany w replikacji). Więcej informacji na ten temat znajdziesz w rozdziale 22. „Replikacja i JRO”. Istnieje kilka sposobów na manipulowanie Autonumerowaniem w aparacie Jet, co nie było możliwe we wcześniejszych wersjach Accessa. Możesz teraz ustawić wartość, o jaką Autonumerowanie będzie przyrastać, a także sprawić, by było odliczane wstecz. Więcej szczegółów na ten temat znajdziesz w rozdziale 5. Mimo iż wartość, o jaką Autonumerowanie przyrasta, może być kontrolowana, pamiętaj, że Autonumerowanie nie oznacza numeru rekordu. Klucze obce i domeny Klucz główny staje się bardzo ważny, gdy chcesz go użyć w innej tabeli. Sytuację taką przedstawiono na rysunku 3.2. Rysunek 3.2. Tabela z dwoma kluczami obcymi Jak widać na rysunku 3.2, można przechowywać wartość klucza głównego jednej tabeli, aby przedstawiać rekordy w innej tabeli. Wówczas mówimy o kluczu obcym, który będzie podstawą opisanych w następnej części relacji. Przedstawiona na rysunku 3.2 tabela trelContactInfo przechowuje dwa obce klucze: ContactID i ContactTypeID. ContactID to klucz główny tabeli tblContact, a ContactTypeID to klucz główny tabeli tlkpContactType. Gdy używasz kluczy obcych, będą się one zawsze znajdować w tej samej domenie. Domeny są to zbiory wartości, z których pobierane są kolumny. Dobrym przykładem jest StudentID. Jego domeną są wszystkie dostępne w systemie numery PESEL. Relacje Gdy definiujesz klucze główne i klucze obce, masz do czynienia z relacjami. Przez relacje rozumiemy zasady obsługiwane na poziomie silnika bazy danych (patrz: Zasada 4. dr Codda). Access wyróżnia trzy różne typy relacji: ? relacja jeden-do-jednego; ? relacja jeden-do-wielu; ? relacja wiele-do-wielu. Aby tworzyć relacje w Accessie, naciśnij znajdujący się w na pasku narzędzi przycisk Relacje lub wybierz Narzędzia==>Relacje, aby otworzyć okno Relacje. Relacja jeden-do-jednego Dwie tabele łączy relacja jeden-do-jednego, gdy każdemu wierszowi z jednej tabeli przyporządkowany jest co najwyżej jeden wiersz z drugiej tabeli. Na rysunku 3.3 znajduje się przykład relacji jeden-do-jednego. Ten typ relacji jest najrzadziej spotykany, ponieważ w większości przypadków możesz powiązane informacje umieszczać w jednej tabeli. Jednakże, ze względów bezpieczeństwa, możesz zdecydować, iż należy informacje rozdzielić na dwie tabele. Również skomplikowane transakcje finansowe zawierają wiele relacji jeden-do-jednego. Rysunek 3.3. Relacja jeden-do-jednego Relacja jeden-do-wielu Najpopularniejszy typ relacji, relacja jeden-do-wielu, występuje wtedy, gdy tabela ma wiele (lub nie ma w ogóle) powiązanych rekordów w drugiej tabeli. Przykładem może być relacja Customer do Order lub przedstawiona na rysunku 3.4 relacja Contact do ContactInfo. Czasami tabela po stronie „jeden” nazywana jest tabelą odnośnika. Zazwyczaj, tabele odnośnika zawierają informacje, które będą przekazywane do innych tabel (na przykład, nazwy województw lub kody pocztowe). Podczas adaptowania konwencji nazewnictwa dobrze jest dla tabeli odnośnika użyć przedrostka tlkp. Rysunek 3.4. Relacja jeden-do-wielu Relacja wiele-do-wielu O relacji wiele-do-wielu mówimy wówczas, gdy każdemu wierszowi z jednej tabeli odpowiada wiele wierszy w drugiej tabeli, a każdemu wierszowi z drugiej tabeli odpowiada wiele wierszy w pierwszej. Jedynym sposobem na przedstawienie w Accessie relacji wiele-do-wielu jest użycie tabeli „łączącej”, w której jako klucze obce znajdują się klucze główne obu tabel. Rysunek 3.5 przedstawia relację wiele-do-wielu między tabelami tblContact i tlkpContactType, utworzoną za pomocą tabeli łączącej trelContactInfo. Tabela tblContact zawiera wszystkie kontakty w bazie danych. Tabela tlkpContactType zawiera sposoby porozumiewania się: Faks, Email, Telefon i Pager. Tabela łącząca zawiera odnośnik do pól Faks i Telefon oraz Kontaktu, tak więc gdy za pomocą pola Kontakt dodaje się do listy nowy sposób porozumiewania się (jak na przykład adres sieci Web), możesz w tabeli odnośnika (tlkpContactType) dodać pozycję „Adres sieci Web” i dodać łączący rekord do tabeli trelContactInfo. To najbardziej elastyczny sposób budowania systemu zarządzania kontaktami, gdyż nie będą występować puste pola, dajmy na to „Telefon2”. Nie będziesz również musiał dodawać nowych pól, gdy będziesz dodawał do listy następny sposób porozumiewania się. Gdy korzystasz z tabeli łączącej, najlepiej jest użyć konwencji nazewnictwa „trel”. Rysunek 3.5. Relacja wiele-do-wielu Podarkusze danych Jedną z nowych opcji Accessa 2000 są podarkusze danych – nowy sposób przeglądania powiązanych danych w widoku arkusza danych. Podarkusze danych, jak ten na rysunku 3.6, są „poszerzonym” widokiem powiązanych danych. Podarkusze danych automatycznie odczytują relacje w bazie i wyświetlają powiązane tabele. Nie zawsze jest to najlepszy sposób na przeglądanie powiązanych danych, tak jak to ma miejsce w przypadku przedstawionej na rysunku 3.6 relacji wiele-do-wielu. Aby zoptymalizować widok podarkuszy danych, możesz utworzyć kwerendę, która połączy dane z powiązanych tabel tak, by wyświetlone były opisy, a nie klucze obce. Następnie otwórz tabelę w widoku Projekt i spójrz na właściwości tabeli (rysunek 3.7). W polu Nazwa podarkusza danych wybierz nazwę utworzonej kwerendy. Być może będziesz również musiał ustawić właściwości podrzędnego i nadrzędnego pola łączącego, jeśli Access nie rozpozna ich automatycznie. Rysunek 3.6. Podarkusz danych Accessa 2000 Rysunek 3.7. Właściwości podarkusza danych Tabela 3.2. Właściwości podarkusza danych Nazwa właściwości Opis Nazwa podarkusza danych Nazwa kwerendy, która posłuży do wypełnienia podarkusza danych Podrzędne pola łączące Pole w podrzędnej tabeli (lub kwerendzie), które ma być połączone z polem w aktualnej tabeli Nadrzędne pola łączące Pole w aktualnej tabeli, które ma być połączone z polem w podrzędnej tabeli lub kwerendzie Wysokość podarkusza danych Wysokość podarkusza danych (w calach) Rozwinięty podarkusz danych Wartość tak/nie, określająca, czy podczas otwierania tabeli podarkusz danych ma być domyślnie rozwinięty Normalizacja danych Zgodnie z zestawem zasad dr Codda proces projektowania bazy danych nazywany jest normalizacją danych. Dr Codd wyróżnia sześć poziomów normalizacji. Skoncentrujemy się tutaj na trzech z nich, gdyż mają one największy wpływ na decyzje dotyczące projektu bazy: ? Pierwsza postać normalna. ? Druga postać normalna. ? Trzecia postać normalna. Pierwsza postać normalna W pierwszej postaci normalnej wszystkie kolumny w tabeli muszą posiadać wartości atomowe. Innymi słowy, każde pole może zawierać tylko jedną wartość, a nie listę wartości lub powtarzającą się grupę danych. Wiele kartotekowych baz danych przechowuje dane w ten sposób, co znacznie utrudnia ich przeszukiwanie. Rysunek 3.8 przedstawia przykład tabeli, która nie jest w pierwszej postaci normalnej, ponieważ w kolumnie ContactInfo przechowywana jest tablica wartości. Rysunek 3.9 jest przykładem tabeli w pierwszej postaci normalnej, gdyż w żadnej z kolumn nie występują powtarzające się informacje. Rysunek 3.8. Tabela jest nie będąca w pierwszej postaci normalnej Rysunek 3.9. Tabela w pierwszej postaci normalnej, ale nie w drugiej postaci normalnej Druga postać normalna Mimo iż tabela przedstawiona na rysunku 3.9 jest w pierwszej postaci normalnej, nie jest jednak w drugiej postaci normalnej. Mówimy, że tabela jest w drugiej postaci normalnej, gdy jest w pierwszej postaci normalnej i jednocześnie każde z jej pól nie będących polem klucza głównego jest w pełni zależne od całego klucza głównego. Innymi słowy, część informacji może być przechowywana w innej tabeli i pobierana z niej poprzez odnośnik. Spójrz na tabelę na rysunku 3.9. Klucz główny składa się z ContactID, ContactInfoID i ContactInfo. Czy kolumna ContactName zależy od części klucza: ContactInfoID i ContactInfo? Nie, gdyż jest zależna od pola ContactID. Aby przekształcić tę tabelę do drugiej postaci normalnej, należy informacje o kliencie umieścić w osobnej tabeli odnośnika i utworzyć pomiędzy tabelami przedstawioną na rysunku 3.10 relację jeden-do-wielu. Tabele te są teraz w drugiej postaci normalnej. Trzecia postać normalna Mimo iż tabele na rysunku 3.10 są w pierwszej i drugiej postaci normalnej, nie są jednak w trzeciej postaci normalnej. Z tabelą w trzeciej postaci normalnej mamy do czynienia, gdy wszystkie pola, nie będące polami klucza głównego, są wzajemnie zależne. Rysunek 3.10. Tabela jest w drugiej postaci normalnej, ale nie w trzeciej postaci normalnej Dobrym przykładem zależności jest pole obliczeniowe (korzystniej jest nie przechowywać pól obliczeniowych, tylko wyświetlać wyniki obliczeń jako część kwerendy). Na rysunku 3.10 druga tabela przechowuje pola ContactInfoID i ContactType (opis). Jeśli wartość pola ContactType poznajesz dzięki polu ContactInfoID, tabela nie jest w trzeciej postaci normalnej. Aby otrzymać trzecią postać normalną, wyodrębnij z ContactInfo trzecią tabelę i utwórz między tabelami ContactInfo i ContactDetails relację jeden-do-wielu, tak jak na rysunku 3.11. Rysunek 3.11. Tabele w trzeciej postaci normalnej Korzyści z normalizacji W poprzednim przykładzie, zyskałeś wiele, normalizując początkową, przedstawioną na rysunku 3.8 tabelę. Tabela początkowa zawierała sposoby porozumiewania się w tablicy wartości, co prawie całkowicie uniemożliwiało przeszukiwanie zawartości pola Faks. Dodatkowo, gdy zmieniał się numer telefonu kontaktu lub zachodziła potrzeba dodania nowego sposobu porozumiewania się, jak na przykład adres e-mail, edycja danych była utrudniona i łatwo było o błędy. Pierwsza postać normalna znacznie poprawiła sytuację i zwiększyła elastyczność w kontrolowaniu numerów telefonów, faksów i adresów e-mail naszych kontaktów. W przedstawionej na rysunku 3.9 tabeli, która jest w pierwszej, lecz nie jest w drugiej postaci normalnej, zarządzanie danymi dotyczącymi kontaktów jest utrudnione, gdyż informacje wielokrotnie się powtarzają. Jeśli masz w bazie 10 numerów telefonów i przechowujesz to samo nazwisko 10 razy, to jest to nie tylko strata przestrzeni dyskowej, ale również problem, gdy zachodzi potrzeba uaktualnienia wszystkich 10 wpisów, gdy dana osoba zmieniła nazwisko. Utrzymanie spójności w tym przypadku może Cię kosztować dużo wysiłku. Tabele na rysunku 3.10, mimo iż są w pierwszej i drugiej postaci normalnej (wszystkie kolumny zależą od całego klucza), nie są w trzeciej postaci normalnej. Przenosząc dane i uzyskując trzecią postać normalną, uzyskujesz większą elastyczność modelu danych, gdyż teraz możesz zarządzać typami kontaktów w osobnej tabeli. Zasady integralności danych Podczas normalizowania danych powinieneś również uwzględnić zasady integralności danych. Większość z zastosowanych zasad będzie zależeć od zdefiniowanych relacji. Podczas określania relacji możesz dodatkowo ustawić kaskadowe aktualizowanie i usuwanie rekordów. Ustawienie aktualizowania kaskadowego rekordów daje Ci pewność, że gdy aktualizujesz wartość klucza podstawowego tabeli „jeden”, zmiana ta odniesie skutek w tabelach „wielu”. Przykładowo, powiedzmy, że masz tabelę odnośnika dla Stanów Zjednoczonych. W tabeli tej znajduje się miasto Nowy Jork, z kluczem podstawowym NY i opisem Nowego Jorku. Wyobraź sobie, że miasto to odłączyło się i stworzyło swój własny stan (to nie jest fikcja, prawie do tego doszło w roku 1789!). Gdy zmienisz wartości NY na NY1 (lub coś bardziej opisowego), wartości NY we wszystkich podrzędnych tabelach zostaną zmienione na NY1. Jeśli aktualizowanie kaskadowe nie było włączone, musiałbyś dodać rekord NY1 do tabeli odnośnika, zaktualizować wszystkie rekordy w podrzędnej tabeli, a następnie usunąć z tabeli odnośnika rekord NY. Włączenie usuwania kaskadowego daje Ci pewność, że gdy usuwasz rekord z tabeli „jeden”, usuniesz również wszystkie rekordy z tabeli „wielu”. Ma to swoje dobre i złe strony. Jeśli usuwasz jednego z klientów, a usuwanie kaskadowe było włączone, usunięte zostaną wszystkie faktury po stronie „wielu”. W przeciwnym wypadku, usunięcie rekordu z tabeli „jeden” nie będzie wykonane, dopóki nie usuniesz wszystkich rekordów z tabeli „wielu”. Rozdział 4. Zaawansowane kwerendy W tym rozdziale: ? Kwerendy w Accesie 2000. ? Tworzenie zaawansowanych kwerend. ? Użycie kwerend. ? Właściwości kwerendy. ? Siatka QBE. ? Panel tabel. ? Siatka kwerendy. ? Kwerendy podsumowujące. ? Użycie kwerend krzyżowych. ? Użycie kwerend parametrycznych. ? Kwerendy przekazujące. ? Kwerendy definiujące dane. ? Optymalizowanie kwerend. Kwerendy są elementami napędowymi baz danych Accessa. Występują w kilku formach i rodzajach. Mogą być zapisywane w bazie (jak tabele) lub działać tylko w pamięci komputera. Do ich tworzenia można używać poleceń SQL lub graficznego interfejsu użytkownika nazywanego tabelą QBE. Kwerenda może zarówno przedstawiać dane w takiej postaci, w jakiej występują w bazie, jak również przed wyświetleniem grupować je i przeliczać. Kwerenda Accessa może już przed uruchomieniem wiedzieć, co powinna wykonać lub zadawać użytkownikowi dodatkowe pytania. Kwerendy potrafią także aktualizować dane, tworzyć i usuwać rekordy, a nawet zmieniać strukturę bazy. Kwerendy w Accessie mogą pracować z danymi przechowywanymi w plikach typu MDB, innych, przyłączonych do Accessa źródłach danych, a nawet bazach danych typu klient-serwer (np. Oracle i Microsoft SQL Server). Są one najszybszym i najpewniejszym sposobem efektywnej interakcji z danymi w relacyjnej bazie danych. Rozdział ten poświęcony jest zaawansowanym odmianom tego potężnego narzędzia. Kwerendy w Accesie 2000 Dokładna konstrukcja bazy danych w połączeniu z możliwościami, jakie dają kwerendy, umożliwiają zaspokojenie części najprostszych, codziennych potrzeb w zarządzaniu danymi. Jednocześnie mogą pomóc w rozwiązaniu najbardziej złożonych problemów, gdyż relacyjna struktura pozwala na logiczne grupowanie danych. Dzięki temu, pomiędzy powiązanymi obiektami można tworzyć użyteczne połączenia. W relacyjnej bazie danych masz wgląd w te dane, których w danym momencie potrzebujesz. Weźmy za przykład rachunek telefoniczny. Raz w miesiącu operator sieci telefonicznej przysyła Ci rachunek za swoje usługi, a jeśli sobie tego zażyczysz – szczegółowy wykaz rozmów. Wykaz ten zawiera wszystkie informacje o przeprowadzonych w poprzednim miesiącu rozmowach telefonicznych: datę, godzinę, numer telefonu osoby, do której dzwoniłeś, czas trwania rozmowy, ilość naliczonych impulsów oraz całkowity koszt rozmowy. To bardzo dużo informacji, jednakże na podstawie samego wykazu trudno jest odpowiedzieć na najbardziej nawet podstawowe pytania. Dużo wygodniej byłoby móc połączyć go z książką adresową. Gdyby to było możliwe, mógłbyś dokładnie stwierdzić, do kogo dzwoniłeś, kiedy to było i ile Cię ta rozmowa kosztowała. Mógłbyś wówczas obliczyć, ile pieniędzy wydałeś na rozmowy z pracownikami danego klienta i na jaką kwotę należy poszczególnych klientów obciążyć. Mogłoby się wydawać, że takiej obróbki danych można dokonać przy użyciu innych narzędzi niż relacyjna baza danych. Jednakże z prawidłowo zaprojektowaną bazą danych obróbka ta będzie banalnie łatwa, wiarygodna i szybka. Tworzenie zaawansowanych kwerend Kwerendy, podobnie jak tabele i formularze, są obiektami bazy danych i przechowywane są w znajdującej się w głównym oknie bazy grupie Kwerendy (skróty do nich mogą być przechowywane w dowolnej, stworzonej przez programistę grupie). Tworzenie kwerend wymaga ustalenia różnych właściwości, które nadzorują sposób, w jaki kwerend, się zachowuje podczas jej uruchamiania. Możesz zacząć od samej kwerendy. Wszystkie zapisane kwerendy możesz przeglądać, klikając obiekt Kwerendy znajdujący się w oknie Grupy głównego okna bazy danych. Kliknięcie prawym przyciskiem myszy którejś z pojedynczych kwerend powoduje wyświetlenie odpowiadającego jej okna dialogowego Właściwości (rysunek 4.1). Rysunek 4.1. Okno dialogowe Właściwości wybranej kwerendy Użycie kwerendy Podobnie jak w przypadku wszystkich innych obiektów baz danych Accessa możesz stosować nazwy o długości nie przekraczającej 255 znaków. Również wszystkie konwencje nazewnictwa używane w przypadku pozostałych obiektów mają zastosowanie do kwerend. Okno Właściwości zawiera także informacje o typie danej kwerendy. Możesz tam również znaleźć jej opis. Jest to bardzo ważna właściwość. Staranny projektant baz danych powinien z niej korzystać tak często, jak tylko to możliwe. Porządny opis umożliwi Ci stwierdzenie, jaką czynność dana kwerenda miała wykonać. Również inni programiści docenią wagę opisu, gdy przyjdzie im pracować z utworzoną przez Ciebie kwerendą. Okno Właściwości zawiera także datę utworzenia kwerendy oraz datę ostatniej modyfikacji, automatycznie aktualizowaną przez Access. Zgodnie z domyślnym ustawieniem właścicielem kwerendy jest osoba, która ją utworzyła. Ma to znaczenie dla zabezpieczeń bazy (temat ten został szczegółowo omówiony w rozdziale 23., „Bezpieczeństwo”). Na dole okna znajdują się dwa pola wyboru. Zaznaczenie pola Ukryty spowoduje, iż obiekt ten nie będzie widoczny dla użytkowników w głównym oknie bazy danych. Dzięki temu będziesz mógł zapobiec przypadkowym zmianom tego obiektu. Pole wyboru Replikowalny informuje, czy dany obiekt jest elementem schematu replikacji, który przygotowałeś dla bazy danych. Mówimy, że obiekt jest replikowalny, gdy poprzez operację replikacji jest modyfikowany przez inny obiekt, najczęściej bardziej aktualną wersję samego siebie. Więcej informacji o replikacji znajdziesz w rozdziale 22. „Replikacja i JRO”. Innym sposobem na ukrycie kwerendy przed uczestnikami jest umieszczenie na początku jej nazwy liter USYS (np. USYS_myquery). Aby przeglądać takie obiekty, musisz w menu Narzędzia otworzyć okno dialogowe Opcje i zaznaczyć pole wyboru Obiekty systemowe. Microsoft również ukrywa różne obiekty, używając do tego celu przedrostka MSYS. Nie możesz dopuścić, by użytkownicy uzyskali dostęp do tych tabel systemowych, bo ich zmiana może doprowadzić do uszkodzenia bazy. Również programiści powinni unikać używania ich, gdyż Microsoft nie gwarantuje umieszczenia ich w kolejnej wersji. Upewnij się, że tabele systemowe są ukryte, zanim przekażesz bazę do rąk użytkowników. Właściwości kwerendy Ponieważ zachowanie kwerendy zależy bezpośrednio od ustawień właściwości, ważnym jest zrozumienie, czym te właściwości są i jak funkcjonują. Tak więc, zanim przejdziemy do zaawansowanych opcji kwerend, przyjrzyjmy się podstawowym kwerendom i określeniom, jakich będziemy używać podczas projektowania bardziej zaawansowanych kwerend. Siatka QBE Access ułatwia Ci tworzenie kwerend, umożliwiając graficzne ich ułożenie w siatce QBE (rysunek 4.2). Wszystkie źródła danych, niezależnie od tego czy są to wbudowane czy dołączane tabele, albo nawet inne kwerendy wybierające, mogą być w taki sam sposób rozmieszczane w siatki QBE. W interfejsie siatki QBE znajdują się relacje między tabelami (tabele i kwerendy wyglądają w niej tak samo), polecenia sortowania i grupowania oraz kryteria. Rysunek 4.2. Siatka QBE podzielona jest na dwie podstawowe części: panel z tabelami u góry i siatkę kwerendy u dołu Kliknij prawym przyciskiem myszy w dowolnym miejscu okna panelu tabel. Z kontekstowego menu wybierz Właściwości, aby wyświetlić właściwości kwerendy. Oto lista wszystkich właściwości kwerendy: ? Opis – taka sama właściwość dostępna jest z poziomu obiektu. ? Wyprowadź wszystkie pola – ustawienie tej właściwości na Tak powoduje ten sam skutek co zaznaczenie opcji Pokaż w każdym polu kwerendy. Dzięki temu również wszystkie pola danej kwerendy są dostępne dla innych kwerend, formularzy i raportów. ? Najwyższe wartości – jeśli chcesz zobaczyć tylko 5 najdroższych produktów, ustaw tę właściwość. Możesz używać również wielkości procentowych. Właściwość ta umożliwia wybranie górnych 5, 10, 25 lub 100 rekordów (albo 5% bądź 25%), lecz możesz ustawić tę opcję w dowolny sposób. Właściwość ta jest stosowana do pola, które w siatce QBE znajduje się najbardziej z lewej strony. Jeśli w kwerendzie, od lewej do prawej znajdują się trzy pola ([nazwa produktu], [koszt jednostkowy] i [cena hurtowa]) i chcesz zobaczyć pięć najdroższych produktów, według [ceny hurtowej], musisz pole [cena hurtowa] posortować malejąco. Jeśli pole [cena jednostkowa] również posortujesz, pięć górnych elementów będzie wyświetlonych na bazie pola [cena jednostkowa]. Jeśli żadne z pól nie jest posortowane, pięć pierwszych rekordów będzie przedstawionych bez sortowania. ? Wartości unikatowe – właściwość ta umożliwia otrzymanie reprezentatywnej listy wartości danego pola. Jeśli podczas pracy z tabelą Zamówienia chcesz zobaczyć, które produkty zostały zamówione, możesz użyć tej właściwości, aby z setek zamówień wyodrębnić kilkadziesiąt produktów. ? Rekordy unikatowe – właściwość ta jest podobna do właściwości Wartości unikatowe, z tą jednak różnicą, że działa na wielu polach. Wynik kombinacji tych pól musi być unikatowy. ? Uaktywnij uprawnienia – podczas zabezpieczania bazy danych musisz mieć możliwość zablokowania tabel w taki sposób, aby użytkownicy nie mogli ich edytować bez Twojej kontroli. Jednocześnie, użytkownicy będą musieli mieć możliwość pracować z tymi tabelami i zawartymi w nich danymi. Poprzez ustawienie tej właściwości możesz pozwolić użytkownikowi uruchamiać kwerendę tak, jakby miał uprawnienia właściciela tabeli. W ten sposób, w zabezpieczonej bazie, użytkownicy mogą w kontrolowany sposób usuwać i aktualizować dane nawet, jeśli ustawione uprawnienia normalnie by im na to nie pozwalały. Bez tej właściwości trudno jest zabezpieczać dane w bazie i jednocześnie umożliwiać użytkownikom wykonywanie na nich operacji. ? Źródłowa baza danych – domyślnie ustawiona jest bieżąca baza danych. To domyślne ustawienie dotyczy również danych dołączanych do innej bazy Accessa. Gdyby dane były umieszczone w innej bazie, z którą nie istniałoby połączenie, właściwość ta zawierałaby ścieżkę dostępu i nazwę pliku. ? Źródłowy ciąg połączenia – właściwość ta zawiera nazwę aplikacji, której użyto do tworzenia zewnętrznego źródła bazy danych. Obie właściwości, Źródłowa baza danych i Źródłowy ciąg połączenia, umożliwiają Accessowi użycie zewnętrznych, niepołączonych danych. ? Blokowanie rekordów – właściwość ta umożliwia określenie, w jaki sposób kwerenda będzie w systemie wieloużytkownikowym rozwiązywać kwestie wielodostępu. Problem taki pojawia się, gdy dwóch lub więcej użytkowników spróbuje dokonać zmian w tym samym rekordzie. Istnieją trzy opcje dla tej właściwości – Bez blokowania, Wszystkie rekordy i Edytowany rekord. Opcje te dotyczą jedynie rekordów związanych z działaniem kwerendy, a nie wszystkich rekordów źródłowej tabeli. Jeśli wybrana została opcja Bez blokowania, możliwe jest dokonywanie zmian w rekordzie przez jednego użytkownika, podczas gdy pracują z nim inni użytkownicy. Pierwszy z nich, który zapisze zmiany na dysku – wygrywa. Access ostrzega użytkowników, że pracują z rekordem, który został zmieniony przez innego użytkownika. Każdy z nich musi zdecydować, jak rozwiązać tę kwestię. Istnieją następujące możliwości – zrezygnować z własnych zmian, nadpisać zmiany innego użytkownika lub też skopiować zmiany do Schowka i później zdecydować, co robić dalej. Po wybraniu opcji Wszystkie rekordy inni użytkownicy nie będą mogli edytować rekordów kontrolowanych przez tę kwerendę, dopóki pierwszy użytkownik nie zakończy pracy. Opcja Edytowany rekord dotyczy jedynie rekordu w danym momencie edytowanego przez użytkownika. ? Typ zestawu rekordów – właściwość ta pozwala na określenie, czy używany przez formularz bądź raport zestaw rekordów to Dynamiczny, Dynamiczny (Niespójny) czy Migawka. Opcja Dynamiczny umożliwia aktualizowanie w relacji strony Wiele. Ustawienie Dynamiczny (Niespójny) umożliwia aktualizowanie obu stron relacji. Ważnym jest zapamiętanie, że użycie opcji Dynamiczny (Niespójny) może mieć poważny wpływ na integralność danych. Najlepiej korzystać z tego ustawienia w momencie, gdy relacja ma włączone wymuszanie więzów integralności i kaskadowe aktualizowanie rekordów i to dopiero po przeprowadzeniu dokładnych testów. Ustawienie Migawka uniemożliwia użytkownikom edytowanie danych, jednakże kwerenda działa wówczas szybciej niż w przypadku dynamicznego zestawu rekordów. Każdy z powyższych wyborów ma wpływ na wydajność i możliwości edytowania danych. ? Czas oczekiwania ODBC – jeśli kwerenda ma korzystać z sieci, właściwość ta określa, jak długo kwerenda ma czekać na rezultaty. Jednostką miary jest sekunda, a domyślne ustawienie to 60 sekund. Mimo iż możesz zmieniać tę liczbę, inne zmienne będą miały wpływ na wydajność. Obciążenie sieci i sposób buforowania plików na serwerze mogą powodować ciągłe zmiany czasu odpowiedzi. Tak więc ustawienie tej wartości musi się odbyć metodą prób i błędów. Ważne, by nie ustawić zbyt długiego oczekiwania, gdyż może się zdarzyć, że użytkownik oczekuje na rezultaty, podczas gdy serwer faktycznie nie działa. ? Filtr – doskonałe narzędzie programistyczne dla początkujących. Coś jak automatyczny konstruktor kwerend. Jeśli użytkownik uruchamia kwerendę, a następnie musi ograniczyć rezultaty, może wybrać wartość w zestawie rezultatów i użyć przycisków filtra, aby wypełnić tę właściwość tak, by przypominała kryteria. Tego wszystkiego może dokonać, nie znając składni sekcji kryteria tabeli QBE. ? Uporządkuj według – ta przypominająca Filtr właściwość umożliwia początkującym użytkownikom uruchomić kwerendę, a następnie zmienić sposób sortowania jej rezultatów poprzez wybranie wartości w zestawie rezultatów. Polecenie dla tego sortowania zawarte jest w tej właściwości. ? Maksymalna liczba rekordów – wpisanie wartości liczbowej w tym polu ogranicza liczbę zwracanych przez kwerendę rekordów, niezależnie od tego ile rekordów w rzeczywistości spełnia kryteria kwerendy. Jeśli kwerenda normalnie zwraca 500 rekordów, a właściwość ta ustawiona jest na 17, to kwerenda zwróci jedynie pierwszych 17 rekordów. Nie ma możliwości otrzymania dodatkowych rekordów bez zmiany tej właściwości. ? Nazwa podarkusza danych (NOWOŚĆ) – to jedna z nowych właściwości w Accessie 2000. Możesz dzięki niej tworzyć kwerendy, które umożliwią Ci dogłębną analizę danych. Gdy utworzyłeś kwerendę wyświetlającą wielkość sprzedaży według produktów, możesz ustawić tę właściwość na tabelę lub kwerendę zawierającą opisy zamówień. Po uruchomieniu kwerendy zobaczysz podsumowanie wielkości sprzedaży według produktów oraz przycisk, po kliknięciu którego zobaczysz szczegóły składające się na tę sumę. ? Podrzędne pole łączące (NOWOŚĆ) – jest to pole podarkusza danych, najczęściej pole klucza, które odpowiada polu w głównej kwerendzie. ? Nadrzędne pole łączące (NOWOŚĆ) – jest to pole głównej kwerendy, najczęściej pole klucza, które odpowiada polu w podarkuszu danych. Aby podarkusz danych działał, pole to musi być widoczne w rezultatach kwerendy. ? Wysokość podarkusza danych (NOWOŚĆ) – wartość w calach, określająca wysokość wyświetlanego podarkusza danych. ? Rozwinięty podarkusz danych (NOWOŚĆ) – jeśli właściwość ta ustawiona jest na Tak, szczegóły podarkusza danych będą wyświetlane po otwarciu kwerendy. Jeśli ustawiona jest na Nie, użytkownik będzie musiał nacisnąć przycisk, aby przejść do szczegółów podarkusza. Mimo iż możliwym jest aktualizowanie danych poprzez podarkusz, zmiany te są uwzględniane w obliczeniach kwerendy dopiero po jej ponownym uruchomieniu. Czas oczekiwania ODBC jest mierzony w sekundach i domyślnie ustawiony na 60 sekund. Jednakże ustawienie tej właściwości na zero nie oznacza, iż kwerenda będzie ciągle „prosiła” o odpowiedź. Ustawienie takie powoduje wyłączenie tej opcji, co sprawia, że nie zostanie wyświetlony żaden komunikat o przekroczeniu czasu oczekiwania. Panel tabel Wszystkie tabele i kwerendy użyte w danej kwerendzie znajdują się w górnym panelu okna – panelu tabel. Wyświetlane są jako niewielkie, zawierające listę pól okna. Jeśli w panelu tym umieścisz kwerendę, wyświetlone zostaną jedynie pola, które mają być umieszczone w rezultatach tej kwerendy. Linia między tabelami przedstawia istniejącą między nimi relację. Relacje ustawione w oknie dialogowym Relacje są tu wyświetlane automatycznie. Funkcja ta nazywa się Autosprzęganie i pozwala Accessowi zakładać istnienie powiązań między polami o tej samej nazwie i tym samym lub kompatybilnym typie danych. Autosprzęganie niespodziewanie tworzy między nimi kwerendę. Może się zdarzyć, że dwa pola o tej samej nazwie nie pozostają ze sobą w relacji, więc sprawdź wszystkie relacje w kwerendzie przed jej użyciem. Możesz wyłączyć Autosprzęganie, otwierając z poziomu menu Narzędzia okno dialogowe Opcje. Opcja Włącz autosprzęganie znajduje się na zakładce Tabele/Kwerendy. Tworzenie relacji w kwerendzie lub pozwolenie na to Accessowi odnosi skutek jedynie dla działania tej kwerendy. Dla osiągnięcia lepszych i bardziej wiarygodnych efektów ustalaj relacje między obiektami w oknie Relacje. Dzięki temu, w razie potrzeby będziesz mógł bez problemów włączyć wymuszanie więzów integralności lub kaskadowe aktualizowanie i usuwanie rekordów. Umieszczanie tabeli lub kwerendy w panelu tabel Umieszczanie tabel lub kwerend w panelu tabel jest proste. Gdy po raz pierwszy tworzysz kwerendę i przechodzisz do widoku Projekt kwerendy, Access „poprosi” Cię o wybranie tabel lub kwerendy, których będziesz chciał używać. Wyświetlone okno dialogowe posiada trzy zakładki, jedną dla tabel, jedną dla kwerend i jedną dla obu typów obiektów. Jeśli musisz dodać tabelę lub kwerendę po zamknięciu tego okna dialogowego, możesz je przywrócić, wybierając z menu Kwerenda opcję Pokaż tabelę. Możesz także użyć znajdującego się na pasku narzędzi przycisku Pokaż tabelę. Górna część okna kwerendy jest dość duża, więc możesz rozszerzać tabele, klikając i przeciągając ich krawędzie. Jeśli kwerenda korzysta z wielu tabel, możliwe jest przesuwanie zawartości okna, dzięki czemu tabele są dobrze widoczne. Możesz również skorzystać z tej przestrzeni i umieścić w niej mniej ważne tabele (np. tabele odnośników), co pozwoli Ci zlikwidować bałagan w tym oknie. Tworzenie relacji w panelu tabel Jeśli nie utworzyłeś relacji między tabelami na poziomie bazy danych poprzez okno Relacje, możesz utworzyć je ad hoc, z poziomu kwerendy. Aby to zrobić, kliknij nazwę pola w jednej tabeli i przeciągnij je na pole w drugiej tabeli. Pomiędzy tymi polami powstanie linia sprzężenia i od tego momentu będą się one zachowywać, jakby istniała między nimi relacja. Do linii sprzężenia mogą być również dołączone takie znaki jak symbol nieskończoności czy cyfra 1. Znaki te informują Cię o charakterze relacji między polami i wyświetlane są, gdy relacja została utworzona na poziomie bazy danych. Jeśli tworzysz relację na poziomie bazy danych, masz do dyspozycji trzy typy relacji: jeden do jednego, jeden do wielu i wiele do wielu. Linia sprzężenia przedstawia charakter relacji poprzez umieszczenie cyfry 1 po stronie jednej relacji i symbolu nieskończoności po stronie wielu. Każdy znak może się znajdować po obu stronach relacji. Istnienie tych znaków nie musi oznaczać, iż faktycznie po stronie jeden występuje jeden rekord, a po stronie wielu jest ich kilka. Określają one jedynie potencjał relacji danych. Ich zadaniem jest pomóc w zdecydowaniu, co z daną kwerendą można zrobić. Jak wszystkie obiekty linia sprzężenia również ma swoje właściwości. W przypadku większości z nich po kliknięciu obiektu prawym klawiszem myszy wyświetlone zostaje menu kontekstowe, z którego można wybrać opcję Właściwości. Właściwości linii sprzężenia wyświetlane są po dwukrotnym kliknięciu linii lewym przyciskiem myszy. Jeśli relacja została utworzona na poziomie bazy danych, możesz z menu Widok wybrać pozycję Właściwości sprzężenia. Czynność tę przedstawia rysunek 4.3. Rysunek 4.3. Możesz otworzyć okno Właściwości sprzężenia, klikając dwukrotnie jego linię Okno właściwości sprzężenia różni się od okien właściwości innych obiektów. Zawiera ono cztery rozwijane listy (dwie z nazwami tabel i dwie z nazwami pól) oraz trzy, wzajemnie wykluczające się pola wyboru. Określają one typ tworzonej relacji. Są to następujące opcje: ? Sprzężenie wewnętrzne – jest to ustawienie domyślne. Ten typ relacji przedstawia prosta linia między dwoma polami. Rezultatem kwerendy z relacją ustaloną na bazie sprzężenia wewnętrznego będą wszystkie rekordy, w których dwa, objęte relacją pola są takie same. Innymi słowy, jeśli kwerenda zawierała klientów i zamówienia, połączone poprzez pola IDklienta, w rezultatach kwerendy znaleźliby się jedynie klienci, którzy złożyli zamówienia i zamówienia powiązane z klientami w tabeli Klienci. ? Lewe sprzężenie zewnętrzne (ang. outer join) – linia przedstawiająca to sprzężenie będzie z jednej strony zakończona strzałką. Ten typ sprzężenia pozwala dominować jednej ze stron. Dominująca strona relacji wskazuje na stronę podporządkowaną. Oznacza to, że kwerenda z Klientami i Zamówieniami, gdzie występowałoby lewe sprzężenie zewnętrzne (linia sprzężenia skierowana w stronę tabeli Zamówienia), wyświetliłaby wszystkich klientów, niezależnie od tego, czy składali jakiekolwiek zamówienia. Jednakże nie wyświetliłaby zamówień nieprzyporządkowanych do żadnego z klientów. ? Prawe sprzężenie zewnętrzne – linia przedstawiająca to sprzężenie również będzie zakończona strzałką z jednej strony. Ten typ relacji również pozwala jednej ze stron dominować. Dominująca strona relacji wskazuje na stronę podporządkowaną. Kwerenda z Klientami i Zamówieniami, gdzie występowałoby prawe sprzężenie zewnętrzne (linia sprzężenia skierowana w stronę tabeli Klienci), wyświetlałaby wszystkie złożone zamówienia, niezależnie od tego, czy były składane przez określonych klientów. Jednakże nie wyświetliłaby klientów, którzy nie składali zamówień. Rozwijane listy w tym oknie dialogowym umożliwiają określenie, których tabel i pól po odpowiedniej stronie sprzężenie ma dotyczyć. Jest to nowe rozwiązanie. Wcześniej, lewa i prawa strona relacji były przedmiotem zmian w zależności od sposobu zbudowania kwerendy. W większości przypadków, integralność referencyjna wymusza użycie prawego bądź lewego sprzężenia zewnętrznego. To tak, jakbyś mógł otrzymać klientów, którzy nie składali zamówień, ale nie mógł jednocześnie otrzymywać zamówień, do których nie ma przyporządkowanych klientów. Jeśli uda Ci się otrzymać nieprzyporządkowane rekordy w wyniku zarówno prawego jak i lewego sprzężenia zewnętrznego tej samej relacji, to znaczy, że coś jest nie w porządku z integralnością danych. Rekordy znajdujące się po podporządkowanej stronie relacji i nie posiadające pary po stronie dominującej nazywamy rekordami osieroconymi. Rekordy zagubione są zazwyczaj niewidoczne podczas zwykłych operacji dokonywanych na bazie danych, jednakże wywołują statystyczne niezgodności w sytuacji, gdy kwerenda oparta jest na podporządkowanej tabeli, bez użycia tabeli dominującej. Innymi słowy, raporty o zamówieniach poszczególnych produktów mogą nie zgadzać się z raportami o zamówieniach według klientów. Ważne, by nie myliły Ci się pojęcia lewe sprzężenie i prawe sprzężenie. Może się zdarzyć, że w tabeli QBE lewe sprzężenie będzie wskazywać w prawo, a prawe w lewo. Jest to mylące zwłaszcza wtedy, gdy już kontrolujesz to, co jest po prawej i to co po lewej stronie. Najważniejsze, byś pamiętał, że dominująca strona wyświetla wszystkie rekordy, nawet jeśli nie odpowiadają one żadnym rekordom ze strony podporządkowanej. Inna z opcji w tym oknie dialogowym umożliwia tworzenie za jego pomocą kolejnej relacji. Kliknięcie przycisku Nowe spowoduje wyświetlenie okna dialogowego, z poziomu którego możesz niespodziewanie ustanowić relację między istniejącymi tabelami. Poniższe rysunki przedstawiają różne rezultaty kwerendy opartej na tabelach Klienci i Zamówienia. Rezultaty sprzężenia wewnętrznego znajdują się na rysunku 4.4, a odpowiadające mu wyrażenie SQL na wydruku 4.1. Rysunek 4.4. Dziesięciu klientów z najmniejszą ilością zamówień w sprzężeniu wewnętrznym Wydruk 4.1. Wyrażenie SQL dla kwerendy z rysunku 4.4 SELECT TOP 10 Klienci.NazwaFirmy, Count(Zamówienia.IDzamówienia) AS PoliczOfIDzamówienia FROM Klienci INNER JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta GROUP BY Klienci.NazwaFirmy ORDER BY Count(Zamówienia.IDzamówienia); Kwerenda ta przedstawia ilość zamówień każdego z klientów i używa sprzężenia wewnętrznego, więc wyświetlane są jedynie rekordy mające swoje odpowiedniki po obu stronach relacji. Porównaj te wyniki z wynikami na rysunku 4.5 i wydrukiem 4.2. Rysunek 4.5. Dwunastu klientów z najmniejszą ilością zamówień w sprzężeniu zewnętrznym Wydruk 4.2. Wyrażenie SQL dla kwerendy z rysunku 4.5 SELECT TOP 10 Klienci.NazwaFirmy, Count(Zamówienia.IDzamówienia) AS PoliczOfIDzamówienia FROM Klienci LEFT JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta GROUP BY Klienci.NazwaFirmy ORDER BY Count(Zamówienia.IDzamówienia); Rysunek 4.4 wygląda zwyczajnie; wszystko wydaje się być w porządku, ale rezultaty kwerendy nie są prawdziwe. Sprzężenie wewnętrzne na rysunku 4.5 wskazuje, iż istnieją dwaj klienci, którzy nie składali żadnych zamówień i nie zostali uwzględnieni w rezultatach kwerendy ze sprzężeniem wewnętrznym. Ponieważ pole wyświetlane po stronie Zamówienia jest sumowane, pokazywany rezultat to zero. Normalnie, brakujący rekord po stronie podporządkowanej byłby przedstawiony jako Null. Kwerenda pokazująca rekordy nie posiadające swoich odpowiedników to po prostu sprzężenie zewnętrzne z kryterium klucza obcego ustawionym na Null. Bez takiego ustawienia kryterium mógłbyś pośród wszystkich rekordów przeoczyć tych kilka pustych pól. Przykład takiej sytuacji przedstawia rysunek 4.6 i wydruk 4.3. Rysunek 4.6. Klienci, którzy nie składali zamówień Wydruk 4.3. Wyrażenie SQL dla kwerendy z rysunku 4.6 SELECT Klienci.NazwaFirmy, Zamówienia.IDzamówienia FROM Klienci LEFT JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta WHERE (((Zamówienia.IDzamówienia) Is Null)); Kwerenda wyświetla dwa rekordy zamiast dziesięciu lub dwunastu, jak to miało miejsce w przypadku braku ustawienia kryterium Null na kluczu obcym. Podsumowując, nie wystarczy, że właściwe pola w odpowiednich tabelach połączone są relacją. Typ tej relacji musi być odpowiedni, by zapewnić zgodny z prawdą zestaw rezultatów kwerendy. Dwie kwerendy oparte na tych samych tabelach i polach mogą dawać zupełnie różne rezultaty, jeśli typ relacji między polami jest różny. Wyrażenia SQL kwerend na rysunkach 4.4 i 4.5 różnią się tylko jednym słowem (spójrz na rysunki 4.7 i 4.8). Jeśli w przykładzie Northwind występowałby rekord zagubiony, inne wyrażenie SQL mogłoby spowodować jego wyświetlenie, po zmianie słowa Left (lewe) na Inner (wewnętrzne) (równie dobrze słowo Inner można zamienić na Right (prawe)). Po raz kolejny otrzymujemy zupełnie inny zestaw rezultatów, zmieniając w relacji zaledwie jedno słowo. Rysunek 4.7. SQL dla sprzężenia wewnętrznego Wydruk 4.4. Wyrażenie SQL dla kwerendy z rysunku 4.7 SELECT TOP 10 Klienci.NazwaFirmy, Count(Zamówienia.IDzamówienia) AS PoliczOfIDzamówienia FROM Klienci INNER JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta GROUP BY Klienci.NazwaFirmy ORDER BY Count(Zamówienia.IDzamówienia); Rysunek 4.8. Dziesięciu\ klientów z najmniejszą ilością zamówień w sprzężeniu wewnętrznym Wydruk 4.5. Wydruk SQL dla kwerendy z rysunku 4.8 SELECT TOP 10 Klienci.NazwaFirmy, Count(Zamówienia.IDzamówienia) AS PoliczOfIDzamówienia FROM Klienci LEFT JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta GROUP BY Klienci.NazwaFirmy ORDER BY Count(Zamówienia.IDzamówienia); Ponieważ istnieją rekordy z takimi samymi wartościami, kwerenda wyświetla 12 rekordów, mimo iż żądano 10 najwyższych. Łatwiej jest zaznaczyć przekątną linię sprzężenia niż pionową czy poziomą. Przemieszczanie tabel lub przesuwanie ich pól może ułatwić Ci wybieranie linii sprzężenia. Siatka kwerendy W dolnej połowie okna znajduje się tabela kwerendy. Tutaj możesz wybrać pola, które mają być widoczne w rezultatach kwerendy, kolejność sortowania, informacje o grupowaniu, obliczenia, informacje o aktualizacji i dołączaniu oraz kryteriach, według których kwerenda będzie wybierać rekordy. Tutaj odbywa się największa część pracy związanej z tworzeniem kwerendy. Umieszczanie pól w siatce kwerendy Umieszczanie pól w kwerendzie może się odbywać na kilka sposobów: ? Dwukrotne kliknięcie – dwukrotne kliknięcie nazwy pola w tabeli powoduje przeniesienie go do pierwszego wolnego miejsca w siatce kwerendy. ? Kliknij i przeciągnij – możesz umieszczać pola, klikając i przeciągając je do dowolnej kolumny w siatce kwerendy. ? Kliknięcie z klawiszem Ctrl – kliknięcie jednego pola, przytrzymanie klawisza Ctrl i kliknięcie innych pól w tej samej tabeli umożliwi Ci przeniesienie ich wszystkich jednocześnie do siatki kwerendy. ? Dwukrotne kliknięcie paska z nazwą tabeli – dwukrotne kliknięcie paska z nazwą tabeli spowoduje zaznaczenie wszystkich jej pól. Przeciągnij zaznaczone w ten sposób pola do siatki kwerendy. Możesz również użyć kliknięcia z klawiszem Ctrl, aby z usunąć niektóre z zaznaczonych pól. ? Gwiazdka – pierwsza pozycja w tabeli to znak gwiazdki. Dwukrotne kliknięcie lub przeciągnięcie go do siatki kwerendy spowoduje utworzenie pojedynczego wpisu w siatce, lecz w rezultatach kwerendy widoczne będą wszystkie pola z tabeli. ? Wybierz pola w siatce kwerendy – pierwszy wiersz siatki kwerendy wskazuje, które pole jest aktualnie używane. Umieszczenie punktu wprowadzania w tym wierszu umożliwi Ci wybór pola. Uważaj, aby przez przypadek nie wybrać pola z niewłaściwej tabeli. Następny wiersz siatki kwerendy, Tabela, może znacznie ułatwić korzystanie z tego sposobu. Użycie drugiego wiersza siatki QBE jest opcjonalne, jednakże w Accessie 2000 jest on stale wyświetlany. Wiersz Tabela wskazuje projektantowi kwerendy, z której tabeli dane pole pochodzi. Ułatwia to pracę, gdy w więcej niż jednej tabeli występują pola o podobnych nazwach. Możesz użyć tego wiersza, aby szybko zmienić tabelę źródłową dla dowolnego z pól w siatce QBE. Określanie kolejności sortowania, wyświetlania rezultatów oraz wybór kryteriów kwerendy Wiersz Sortuj umożliwia Ci określenie sposobu, w jaki kwerenda sortuje wiersze rezultatów. Każde z pól możesz sortować Rosnąco, Malejąco lub pozostawić je bez sortowania. Gdy do sortowania wybrane jest więcej niż jedno pole, o kolejności sortowanie decyduje kolejność pól od lewej do prawej. Czwarty wiersz określa, czy pole jest wyświetlane w rezultatach kwerendy. Nawet, jeśli pole nie jest wyświetlane, wciąż może wpływać na rezultaty kwerendy. Aby kwerenda była wykonywana, co najmniej jedno pole musi być wyświetlane w jej rezultatach. Piąty i wszystkie pozostałe wiersze przeznaczone są dla warunków. Wiersze dotyczące warunków zawierają wartości służące do wybierania wierszy do zestawu rekordów. Mogą również zawierać procedury SQL, jednakże technika ta nie jest zalecana, gdyż procedury SQL muszą być wykonywane dla każdego rekordu w możliwym zestawie rezultatów kwerendy, zanim zostanie wyświetlony rezultat końcowy. Zazwyczaj ten sam efekt można uzyskać przez użycie podkwerend. Możesz wielokrotnie dodawać pola do tabeli QBE, wyłączać opcję Pokaż i kontrolować sortowanie zestawu rezultatów bez zmieniania kolejności pól. Jeśli zajdzie taka potrzeba, do tabeli QBE możesz dodać kolejny wiersz: Podsumowanie. Aby uzyskać dostęp do tego wiersza kliknij znajdujący się na pasku narzędzi przycisk Sumy lub wybierz tę opcję z menu Widok. Włączenie opcji Sumy zmienia nieco charakter kwerendy. Te zagregowane kwerendy pozwalają Ci na twórcze kształtowanie zestawu rezultatów. Szczegóły użycia wiersza Podsumowanie omówione zostaną w następnej części tego rozdziału. Kwerendy podsumowujące Zazwyczaj zestaw rezultatów kwerendy zawiera tak wiele informacji, że jest dla użytkownika bezużyteczny. Aby to zmienić, Access umożliwia Ci tworzenie podsumowania danych za pomocą kwerend podsumowujących. Aby utworzyć podsumowanie klientów i ich zakupów, możesz w dołączonej do Accessa 2000 bazie Northwind utworzyć nową kwerendę. Gdy skończysz, kwerenda będzie wyświetlać listę klientów i zakupionych przez nich produktów jako listę unikatowych kombinacji. Aby rozpocząć pracę z tą kwerendą, umieść w panelu tabel następujące tabele: Klienci, Zamówienia, Opisy zamówień i Produkty. Z tabeli Klienci przenieś do siatki kwerendy pole NazwaFirmy, a z tabeli Produkty – pole NazwaProduktu. Posortuj kwerendę według NazwaFirmy i NazwaProduktu. Uruchom kwerendę, klikając znajdujący się na pasku narzędzi symbol czerwonego wykrzyknika lub wybierając Kwerenda==>Uruchom. Jeśli dokładnie przyjrzysz się rysunkowi 4.9, zauważysz, że niektórzy z klientów występują w zestawie rezultatów więcej niż raz. Wyrażenie SQL dla rysunku 4.9 znajduje się na wydruku 4.6. Wydruk 4.6. Wyrażenie SQL dla kwerendy z rysunku 4.9 SELECT Klienci.NazwaFirmy, Produkty.NazwaProduktu FROM Produkty INNER JOIN ((Klienci INNER JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta) INNER JOIN [Opisy zamówień] ON Zamówienia.IDzamówienia = [Opisy zamówień].IDzamówienia) ON Produkty.IDproduktu = [Opisy zamówień].IDproduktu ORDER BY Klienci.NazwaFirmy, Produkty.NazwaProduktu; Rysunek 4.9. Niektórzy klienci pojawiają się kilkakrotnie dla tego samego produktu, gdyż zamówili go więcej niż raz Powróć do widoku Projekt kwerendy i kliknij znajdujący się na pasku narzędzi przycisk Sumy lub wybierz tę opcję z menu Widok. Wiersz podsumowania pojawi się w siatce kwerendy z wybraną dla obu pól opcją Grupuj według. Oznacza to, że kwerenda zmniejszy rozmiar zestawu rekordów tak, by wyświetlał tylko jeden raz każdą kombinację wartości NazwaFirmy i NazwaProduktu. Uruchom kwerendę ponownie, a zobaczysz, że nazwy firm i produktów się nie powtarzają. Spowodowało to usunięcie z zestawu setek rekordów. Możesz korzystać z opcji Grupuj według nawet dla dziesięciu pól, pamiętaj jednak, że użycie tej opcji dla każdego zbędnego pola spowalnia pracę kwerendy i powoduje wyświetlenie dodatkowych wierszy w zestawie rezultatów. Używaj opcji Grupuj według tylko dla pól, które są niezbędne dla uzyskania pożądanych rezultatów. W polu z zaznaczoną opcją Grupuj według nie możesz wprowadzać wartości [nazwatabeli].*. Opcja Sumy jest rozbudowana i posiada wiele innych możliwości. Wprowadzając do kwerendy wiersz Podsumowanie, masz do dyspozycji dwanaście opcji. Dziewięć z nich to funkcje agregujące, co oznacza, że wykonują one na danych różne obliczenia. Teraz przyjrzymy się każdej z nich. Żadna z funkcji agregujących nie uwzględnia w swoich obliczeniach wartości Null. Jeśli chcesz to zmienić, musisz przekształcić wartości Null na zera, korzystając z kwerendy aktualizującej lub polecenia IIF(IsNull([nazwapola]),0,[nazwapola]), aby kwerenda wyświetlała wartości zero. Funkcja agregująca Policz Aby zobaczyć, ile zamówień złożył każdy z klientów, musisz zmodyfikować kwerendę. Zamiast pola NazwaProduktu wprowadź z tabeli Zamówienia pole IDzamówienia i w wierszu Podsumowanie wybierz wartość Policz. Usuń z panelu tabele Opisy zamówień i Produkty. Gdy uruchamiasz kwerendę agregującą ważne jest, by nie znajdowało się w niej nic zbędnego. Prawie wszystko co znajduje się w siatce QBE może mieć wpływ na działanie funkcji agregującej. Jeśli nie usuniesz tych tabel (mimo iż nie używasz ich w siatce QBE), spowodują one, że kwerenda będzie zliczać wszystkie zamówione produkty, a nie zamówienia (rysunek 4.10 i wydruk 4.7). Rysunek 4.10. Zliczanie zamówień klientów Wydruk 4.7. Wyrażenie SQL dla kwerendy z rysunku 4.10 SELECT Klienci.NazwaFirmy, Count(Zamówienia.IDzamówienia) AS PoliczOfIDzamówienia FROM Klienci INNER JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta GROUP BY Klienci.NazwaFirmy Zauważ, że na rysunku 4.10 nie zachodzi potrzeba określenia kolejności sortowania. Prosta kwerenda agregująca sama sortuje rezultaty według pola grupowania. Jeśli nie określisz kolejności sortowania, określana jest ona przez położenie od lewej do prawej strony pól z opcją Grupuj według. Funkcja agregująca Średnia Aby zobaczyć średnią cenę danej kategorii produktów, utwórz kwerendę opartą jedynie na tabeli Produkty. W siatce kwerendy umieść pola IDkategorii i CenaJednostkowa, dodaj wiersz Podsumowanie i ustaw opcję podsumowania w polu CenaJednostkowa na Średnia (rysunek 4.11 i wydruk 4.8). Rysunek 4.11. Siatka QBE kwerendy obliczającej średnią Wydruk 4.8. Wyrażenie SQL dla kwerendy z rysunku 4.11 SELECT Produkty.IDkategorii, Avg(Produkty.CenaJednostkowa) AS ŚredniaOfCenaJednostkowa FROM Produkty GROUP BY Produkty.IDkategorii; Funkcja agregująca Średnia działa zarówno na polach typu Liczba, Data/Godzina, Walutowy i Autonumerowanie i wyświetla średnią wartość danej grupy pól. Funkcje agregujące Minimum i Maksimum Funkcje Min/Maks mogą być przydatne, gdy chcesz uzyskać największą wartość w danym polu. Na przykład w sytuacji, gdy chcesz zobaczyć datę ostatniego zamówienia każdego z klientów. Aby tego dokonać, utwórz kwerendę z tabelami Klienci i Zamówienia, połączonymi za pomocą pola IDklienta. Umieść w siatce kwerendy pola NazwaFirmy i DataZamówienia. Dodaj wiersz Podsumowanie i ustaw opcję podsumowania pola DataZamówienia na Maksimum. Uzyskasz w ten sposób datę ostatniego zamówienia każdego z klientów. Ustawienie tej opcji na Minimum spowoduje wyświetlenie najwcześniejszego, zarejestrowanego zamówienia każdego z klientów. Możesz nawet wyświetlać je obok siebie, dodając ponownie pole DataZamówienia i wybierając Maksimum dla jednego i Minimum dla drugiego z nich. Funkcje agregujące Pierwszy i Ostatni Na pierwszy rzut oka, funkcje Pierwszy i Ostatni mogą przypominać Minimum i Maksimum, w rzeczywistości jednak bardzo się od siebie różnią. Minimum i Maksimum oceniają przedstawiane dane. Pierwszy i Ostatni po prostu pobierają pierwszą lub ostatnią wartość napotkaną przez kwerendę, co czasami daje zaskakujące rezultaty. Radzimy z ostrożnością korzystać z tych funkcji, najlepiej na uprzednio posortowanych, tymczasowych tabelach. Użycie tych opcji na nieposortowanej lub posortowanej w niewłaściwy sposób tabeli da subiektywne wyniki. Stanie się tak dlatego, że dla funkcji Pierwszy i Ostatni najważniejsza jest kolejność przedstawienia pól, a powiązania danych z innymi polami są nieważne. Funkcji tych użyjesz, aby uzyskać listę najdroższych produktów w każdej kategorii. Lista ta będzie zawierać pola NazwaKategorii, NazwaProduktu i CenaJednostkowa. Utwórz nową kwerendę, opartą na tabelach Kategorie i Produkty. W siatce QBE umieść pole NazwaKategorii z tabeli Kategorie oraz pola NazwaProduktu i CenaJednostkowa z tabeli Produkty. Ustaw kolejność sortowania pola NazwaKategorii na Rosnąco i CenaJednostkowa na Malejąco. Z menu Kwerenda wybierz Kwerenda tworząca tabele i nazwij nową tabelę Kategorie i Produkty Sortowane według Ceny. Uruchom kwerendę. W nowej tabeli powinno znaleźć się ponad 70 nowych rekordów. Teraz możesz utworzyć kwerendę korzystającą z funkcji Pierwszy i Ostatni. Utwórz nową kwerendę i wyświetl w panelu tabelę Kategorie i Produkty sortowane według ceny. Wszystkie jej pola umieść w siatce kwerendy. Dodaj wiersz Podsumowanie i ustaw funkcję agregującą w polu NazwaProduktu na Pierwszy, a następnie w polu CenaJednostkowa również na Pierwszy. Uruchom kwerendę, a zobaczysz najdroższy produkt w każdej kategorii. Jeśli funkcje Pierwszy zamienisz na Ostatni, zobaczysz najtańszy produkt w każdej kategorii. Ustawienie jednego z pól na Pierwszy, a drugiego na Ostatni pokaże, jak funkcje te pobierają dane z różnych wierszy w zestawie rekordów, ale przedstawia je tak, jakby były częścią tego samego rekordu. Spróbuj użyć takiej samej kwerendy na początkowej tabeli, a zobaczysz jak bardzo funkcje Pierwszy i Ostatni zależą od uprzedniego sortowania. Aby funkcje Pierwszy i Ostatni działały efektywnie, sortowanie rekordów musi być wykonane świadomie (tak jak zrobiliśmy to w tymczasowej tabeli) lub poprzez indeksy tabel. W tym konkretnym przykładzie, funkcje Pierwszy i Ostatni mogłyby być zastąpione przez Minimum i Maksimum, jednakże w przypadku pola NazwaProduktu możliwe byłoby jedynie użycie tych pierwszych. Funkcje agregujące Odchylenie standardowe i Wariancja Odchylenie standardowe (OdchStd) i Wariancja dokonują obliczeń na wartościach danego pola. Wystarczy utworzyć kwerendę grupującą dane w dowolny sposób. Zaznacz odpowiednie pole i ustaw opcję wiersza Podsumowanie na OdchStd lub Wariancja. Odchylenie standardowe i Wariancja wykorzystują metodę próbkowania opartą na mianowniku (n – 1), gdzie n równe jest liczbie rekordów w zestawie rezultatów. Metoda ta używana jest w analizie statystycznej. Kolejne dwie opcje podsumowujące – Wyrażenie i Gdzie – nie są funkcjami agregującymi. Funkcja Wyrażenie Wyrażenie umożliwia przedstawienie obliczeń w rezultatach kwerendy, jednakże obliczenia te muszą zawierać funkcję agregującą. Używaj tej opcji, gdy chcesz w kwerendzie przedstawić wynik wielu funkcji. Przykładowe wyrażenie znajduje się na rysunku 4.12 (wyrażenie SQL na wydruku 4.9). Rysunek 4.12. Zestaw rezultatów z wyrażeniem Wydruk 4.9. Wyrażenie SQL dla kwerendy z rysunku 4.12 SELECT Kategorie.NazwaKategorii, Count(Produkty.NazwaProduktu) AS PoliczOfNazwaProduktu, Sum([CenaJednostkowa])*1.05 AS [Przykladowe Wyrażenie] FROM Kategorie INNER JOIN Produkty ON Kategorie.IDkategorii = Produkty.IDkategorii GROUP BY Kategorie.NazwaKategorii; W tym przykładzie zliczasz produkty, a następnie podnosisz średnią cenę każdej kategorii o 5%. Aby tego dokonać, ustawiasz wartość wiersza Podsumowanie danego pola na Wyrażenie, a następnie zapisujesz wzór używający funkcji agregującej. Jeśli w zapisanym wyrażeniu brak będzie funkcji agregującej, Access wyświetli komunikat o błędzie, a kwerenda nie zostanie wykonana. Warunek Gdzie Zastosowanie kryteriów w kwerendzie agregującej odbywa się przez użycie polecenia Gdzie lub przez wprowadzenie kryteriów do siatki QBE, jak to ma miejsce w przypadku zwykłej kwerendy wybierającej. Istnieją jednak różnice między tymi sposobami i wybór ich może mieć wpływ na zachowanie kwerendy. Podczas użycia polecenia Gdzie kwerenda najpierw stosuje kryteria, dołączając lub wyłączając rekordy, zanim zostaną one pogrupowane. Jeśli wprowadzisz kryteria w innym polu bez użycia polecenia Gdzie, kryteria będą stosowane dopiero po zakończeniu grupowania. Przed kryteriami wyrażonymi bez użycia polecenia Gdzie, w SQL występować będzie polecenie Having. Różnice są proste, lecz bardzo ważne. Jeśli z kwerendy agregującej chcesz usunąć sprzedaż zagraniczną, użyj polecenia Gdzie. Jeśli chcesz jednocześnie zobaczyć jedynie rezultaty, których wynik zliczania jest wyższy niż 1000, wyraź to w polu wykonującym polecenie Policz. Kryterium wykluczające sprzedaż zagraniczną powinno być wpisane w siatce kwerendy dla pola KrajOdbiorcy i wyrażone w SQL za pomocą wyrażenia Having. Polecenie Having przydaje się przy stosowaniu kryteriów na dokonanych obliczeniach. Przykłady użycia tego polecenia znajdują się na rysunku 4.13 i wydruku 4.10. Rysunek 4.13. Kwerenda używająca pleceń Where i Having w siatce QBE Wydruk 4.10. Wyrażenie SQL dla kwerendy z rysunku 4.13 SELECT Kategorie.NazwaKategorii, Count(Produkty.NazwaProduktu) AS PoliczOfNazwaProduktu, Sum([Opisy zamówień].Ilość) AS SumaOfIlość FROM (Kategorie INNER JOIN Produkty ON Kategorie.IDkategorii = Produkty.IDkategorii) INNER JOIN ((Klienci INNER JOIN Zamówienia ON KLienci.IDklienta = Zamówienia.IDklienta) INNER JOIN [Opisy zamówień] ON Zamówienia.IDzamówienia = [Opisy zamówień].IDzamówienia) ON Produkty.IDproduktu = [Opisy zamówień].IDproduktu WHERE (((Zamówienia.KrajOdbiorcy)="USA")) GROUP BY Kategorie.NazwaKategorii HAVING (((Sum([Opisy zamówień].Ilość))>1000)); Łatwym sposobem na zapamiętanie kolejności wykonywania wyrażeń z fraz Where i Having jest przeglądanie wyrażeń SQL tworzonych przez każdą kwerendę. Fraza Having zawsze jest za frazą Group by. Użycie kwerend krzyżowych Kwerendy krzyżowe i agregujące są do siebie bardzo zbliżone. Kwerenda krzyżowa posiada wiele zdolności analitycznych. W typowej kwerendzie wybierającej pola wyświetlane są u góry zestawu rezultatów, a lista wartości poniżej, jako pojedyncze rekordy. W kwerendzie agregującej pola również znajdują się u góry zestawu rezultatów, jednakże poniżej wyświetlane są wartości będące podsumowanymi danymi. Kwerenda krzyżowa umożliwia Ci tak przekształcić podsumowania uzyskane dzięki kwerendzie agregującej, że wartości będące rezultatami jednej z grup rozmieszczone są u góry zestawu rezultatów. Utworzona przez lewą kolumnę i górny wiersz zestawu rezultatów macierz wypełniana jest żądanymi przez Ciebie obliczeniami. W wyniku tego otrzymujemy coś na kształt tabeli przestawnej. Prosta kwerenda krzyżowa składa się przynajmniej z trzech elementów: Nagłówka wiersza, Nagłówka kolumny i Wartości. Kwerenda ta może korzystać z zestawu rezultatów dowolnej kwerendy wybierającej. Aby utworzyć kwerendę krzyżową, w wyniku której podzielimy klientów według kategorii zamawianych produktów, będziemy potrzebować następujących tabel: Klienci, Kategorie, Produkty, Zamówienia i Opisy zamówień. Z tabeli Klienci wybierz pole NazwaFirmy, z tabeli Kategorie pole NazwaKategorii, a z tabeli Opisy zamówień pole Ilość. Aby kwerendę wybierającą przekształcić w krzyżową, wybierz z menu Kwerenda opcję Kwerenda krzyżowa. Po przekształceniu w siatce kwerendy pojawi się nowy wiersz (rysunek 4.14 i wydruk 4.11). Wiersz ten umożliwi Ci przyporządkowanie pola do odpowiednich elementów kwerendy krzyżowej. Pole NazwaFirmy ustaw jako Nagłówek wiersza, pole NazwaKategorii jako Nagłówek kolumny (ta część będzie wyświetlana u góry zestawu rezultatów), pole Ilość jako Wartość, a w wierszu Podsumowanie tego pola wybierz Suma. Po uruchomieniu kwerendy Access automatycznie utworzy sumę na każdym przecięciu klienta i produktu. Rysunek 4.14. Kwerenda krzyżowa w siatce QBE Wydruk 4.11. Wyrażenie SQL dla kwerendy z rysunku 4.14 TRANSFORM Sum([Opisy zamówień].Ilość) AS SumaOfIlość SELECT Klienci.NazwaFirmy FROM (Kategorie INNER JOIN Produkty ON Kategorie.IDkategorii = Produkty.IDkategorii) INNER JOIN ((Klienci INNER JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta) INNER JOIN [Opisy zamówień] ON Zamówienia.IDzamówienia = [Opisy zamówień].IDzamówienia) ON Produkty.IDproduktu = [Opisy zamówień].IDproduktu WHERE (((Zamówienia.DataZamówienia) Between #1/1/1998# And #12/31/1998#)) GROUP BY Klienci.NazwaFirmy PIVOT "Q" & CStr(DatePart("Q",[DataZamówienia])); Możliwe jest ustawienie w kwerendzie krzyżowej więcej niż jednego pola jako Nagłówka wiersza, jednakże może być tylko jeden Nagłówek kolumny i jedna Wartość. To dałoby hierarchiczny widok danych, ze wzrastającym stopniem szczegółowości wraz z przesuwaniem się od lewej do prawej. Aby zobaczyć jak to działa, możesz jako Nagłówki wiersza dodać pola Kraj i Region. W polu Wartość możesz wprowadzić również własne obliczenia. Zamień w siatce Ilość na następujące wyrażenie: Expr1: IIF(Sum([Ilość])>=50, "High", "Low") Ten fragment kodu korzysta z funkcji agregującej, aby wyświetlić wartość w kwerendzie krzyżowej. W wierszu Podsumowanie dla tego pola ustaw wartość Wyrażenie. Po uruchomieniu kwerendy w tabeli zobaczysz wynik IIf(). Wyrażenia, które tworzysz w kwerendzie krzyżowej, muszą być kompatybilne z wyrażeniami, które napisałbyś dla innej kwerendy agregującej. W podobny sposób kwerenda może zawierać wynik wyrażenia w nagłówku wiersza bądź kolumny. Poniższa kwerenda (przedstawiona na rysunkach 4.15 i 4.16 oraz wydruku 4.12) korzysta z wyrażenia, aby podzielić dane w nagłówkach kolumn na ćwiartki. Wyrażenie przestawne wygląda w następujący sposób: "Q" & CStr(DatePart("Q", [OrderDate])) Wydruk 4.12. Wyrażenie SQL dla kwerend z rysunków 4.15 i 4.16 TRANSFORM Sum([Opisy zamówień].Ilość) AS SumaOfIlość SELECT Klienci.NazwaFirmy FROM Kategorie INNER JOIN (Produkty ON Kategorie.IDkategorii = Produkty.IDkategorii) INNER JOIN ((Klienci INNER JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta) INNER JOIN [Opisy zamówień] ON Zamówienia.IDzamówienia = [Opisy zamówień].IDzamówienia) ON Produkty.IDproduktu = [Opisy zamówień].IDproduktu) WHERE (((Zamówienia.DataZamówienia) Between #1/1/1998# And #12/31/1998#)) GROUP BY Klienci.NazwaFirmy PIVOT "Q" & CStr(DatePart("Q", [DataZamówienia])); Aby kwerenda krzyżowa uwzględniła dokonane zmiany, musisz ją zamknąć i na nowo otworzyć. Rysunek 4.15. Zmodyfikowana kwerenda krzyżowa w siatce QBE Rysunek 4.16. Zestaw rezultatów zmodyfikowanej kwerendy krzyżowej Użycie kwerend parametrycznych Kwerendy parametryczne nie są osobnym typem kwerend. Wymagają one po prostu interwencji użytkownika. Wszystkie kwerendy przed ich uruchomieniem mogą żądać podania określonych informacji. Pewnie zdarzyło Ci się podczas tworzenia kwerendy wprowadzić niepoprawną nazwę pola lub wartość. Gdy próbowałeś uruchomić tę kwerendę, zostałeś poproszony o zidentyfikowanie tych informacji. Jeśli faktycznie Ci się to przydarzyło, stworzyłeś wówczas kwerendę parametryczną. Teraz również to zrobisz, jednakże będziemy kontrolować to, co się dzieje. Dobrym przykładem będzie kwerenda oparta na tabeli Klienci i zawierająca pola NazwaFirmy, Przedstawiciel i Telefon. Kwerenda ta przedstawiona jest na rysunku 4.17, a odpowiadające jej wyrażenie SQL znajduje się na wydruku 4.13. Rysunek 4.17. Podstawa dla prostej kwerendy parametrycznej Wydruk 4.13. Wyrażenie SQL dla kwerendy z rysunku 4.17 SELECT Klienci.NazwaFirmy, Klienci.Przedstawiciel, Klienci.Telefon FROM Klienci ORDER BY Klienci.Przedstawiciel; Gdy uruchomisz tę kwerendę, otrzymasz listę wszystkich klientów, ich przedstawicieli oraz wszystkich numerów telefonów. Można jednak wprowadzić wartość kryterium w taki sposób, aby uzyskać informacje o przedstawicielu konkretnego klienta. Ilustruje to rysunek 4.18 i wydruk 4.14. Wydruk 4.14. Wyrażenie SQL dla kwerendy z rysunku 4.18 SELECT Klienci.NazwaFirmy, Klienci.Przedstawiciel, Klienci.Telefon FROM Klienci WHERE (((Klienci.NazwaFirmy)="Frankenversand")) ORDER BY Klienci.Przedstawiciel; Działa całkiem nieźle, jednakże dość męczące jest każdorazowe modyfikowanie kryteriów i uruchamianie kwerendy. Rozwiązanie to jest także mało praktyczne, jeśli z tej aplikacji mają korzystać osoby nie zaznajomione z siatką QBE Accessa. Zamiast tego możesz utworzyć parametr dla tej kwerendy i pozwolić mu funkcjonować jako prymitywny interfejs dla użytkowników. Dzięki użyciu kwerendy parametrycznej kryteria są zmieniane, a użytkownicy nie muszą borykać się z projektowaniem kwerendy. Rysunek 4.18. Kwerenda z prostym kryterium w siatce QBE Tworzenie parametrów dla kwerendy w siatce QBE Aby utworzyć parametr w siatce QBE, wybierz z menu Kwerenda opcję Parametry. Wyświetlone zostanie okno dialogowe, w którym możesz umieścić parametry, które chcesz ustawić. Mimo iż można tworzyć kwerendy parametryczne bez użycia okna dialogowego, umożliwia ono kontrolowanie kolejności przedstawiania parametrów oraz typów danych dla każdego z nich. Po umieszczeniu parametrów w oknie dialogowym możesz rozmieścić je na właściwych miejscach w siatce kwerendy. Parametr w siatce kwerendy musi dokładnie odpowiadać parametrowi w oknie dialogowym. Jeśli parametr będzie istniał jedynie w oknie dialogowym, kwerenda poprosi użytkownika o podanie informacji, jednakże nie będzie wiedzieć, jak ma je zastosować. W kwerendzie opartej na tabelach Klienci, Zamówienia, Opisy zamówień i Produkty umieść pola IDklienta, NazwaFirmy, DataZamówienia, NazwaProduktu, CenaJednostkowa, Ilość i Rabat. Posortuj kwerendę malejąco według DataZamówienia i rosnąco według NazwaProduktu. Z menu Kwerenda wybierz opcję Parametry. Wprowadź pierwszy parametr jako ID klienta z typem danych tekst. W pierwszej linii sekcji kryteria pola IDklienta wprowadź [ID klienta]. Jest to informacja dla kwerendy, że ma akceptować parametr tekstowy nazwany ID klienta i użyć go w kwerendzie jako kryterium pola IDklienta. Ta kwerenda parametryczna przedstawiona jest na rysunku 4.19, a odpowiadające jej wyrażenie SQL na wydruku 4.15. Wydruk 4.15. Wyrażenie SQL dla kwerendy z rysunku 4.19 PARAMETERS [ID Klienta] Text; SELECT Klienci.NazwaFirmy, Zamówienia.IDzamówienia, Zamówienia.DataZamówienia, Produkty.NazwaProduktu, [Opisy zamówień].CenaJednostkowa, [Opisy zamówień].Ilość, [Opisy zamówień].Rabat FROM Produkty INNER JOIN ((Klienci INNER JOIN Zamówienia ON Klienci.IDklienta = Zamówienia.IDklienta) Rysunek 4.19. Umieszczanie parametru w kwerendzie w siatce QBE INNER JOIN [Opisy zamówień] ON Zamówienia.IDzamówienia = [Opisy zamówień].IDzamówienia) ON Produkty.IDproduktu = [Opisy zamówień].IDproduktu WHERE (((Klienci.IDklienta)=[IDklienta])) ORDER BY Zamówienia.DataZamówienia DESC, Produkty.NazwaProduktu; Uruchom kwerendę i w odpowiedzi na pytanie o parametr wpisz Quick. W zestawie rezultatów znajdą się wszystkie rekordy, w których IDklienta to Quick. Parametrem może być zdanie o maksymalnej długości 255 znaków. Umożliwia to zadawanie użytkownikom pytań o kryteria w bardziej zrozumiały lub po prostu bardziej grzeczny sposób. Zmień parametr i sposób jego przedstawienia na Proszę wprowadzić kod klienta. Teraz kwerenda, pytając klienta, użyje powyższego zdania. Tworzenie parametrów w kwerendach korzystających z programu Kwerendy parametryczne mogą działać w aplikacjach w inny sposób – poprzez program. Parametry tworzą w kwerendzie zbiór, do którego możesz zwracać się podczas wykonywania kwerendy w kodzie VBA. Ma to swoje dobre strony. W interfejsie użytkownika możesz pobrać wszystkie parametry poprzez formularz, jednocześnie kontrolując typ danych i ich poprawność, a następnie umieścić je wszystkie w kwerendzie parametrycznej. Umożliwia to użytkownikowi całościowe przeglądanie tego, co wpisuje, i dokonywanie zmian przed otrzymaniem zestawu rekordów. Podczas normalnego wykonywania kwerendy parametrycznej użytkownik nie ma możliwości powrotu do poprzednich parametrów. Po wpisaniu wartości może jedynie iść dalej lub anulować kwerendę. Tworzenie kwerend parametrycznych – siatka QBE a program Często programiści wykonują procedury SQL poprzez kod. W wielu przypadkach sposób ten sprawdza się doskonale, jednakże nie jest pozbawiony wad. Po pierwsze, procedury SQL mogą być niezrozumiałe lub niedostępne dla innych, mniej doświadczonych programistów, których zadaniem w przyszłości może być obsługa tej aplikacji. Może to doprowadzić do błędów w jej działaniu. Użycie kwerendy parametrycznej umożliwia innym programistom, posiadającym oczywiście odpowiednie uprawnienia, modyfikowanie kwerendy poprzez siatkę QBE, co może być uważane za wspólny mianownik użytkowników i programistów Accessa. Najważniejszy jest fakt, że w większości przypadków kwerenda parametryczna jest najszybszym i najbardziej wiarygodnym sposobem na wykonywanie kwerendy bez zmiany jej kryteriów lub właściwości. Dzieje się tak, ponieważ Access kompiluje kwerendy, więc Jet ma już gotowy ich profil wykonywania. Krótko mówiąc, ciąg SQL w kodzie nie jest zoptymalizowany, a kwerenda parametryczna może być optymalizowana. Kiedy kwerenda parametryczna jest we właściwy sposób wykonywana poprzez program, użytkownik nie jest proszony o podawanie żadnych informacji. Wykonywanie kwerendy parametrycznej poprzez program Teraz pokażemy, w jaki sposób kwerenda parametryczna może być wykonywana poprzez kod. Wydruk 4.16 akceptuje nazwę kwerendy i jeden parametr, a następnie używa tych argumentów, aby otworzyć daną kwerendę i policzyć jej rekordy. Zwracana wartość to ilość rekordów w zestawie rekordów. Możesz uruchamiać tę funkcję z okna Analiza programu lub poprzez zdarzenie na formularzu. Wydruk 4.16. Funkcja wykonująca kwerendę parametryczną poprzez kod Function RunParameterQuery (QryName As String, CustID As String) 'Funkcja ta uruchomi kwerendę parametryczną, która 'pobiera ID klienta jako argument 'Argumenty: ' QryName – Nazwa kwerendy parametrycznej ' CustID – Ciąg identyfikujący klienta 'Z "Access 2000 – Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim db As Database Dim qrydef As QueryDef Dim rs As Recordset Set db = CurrentDb() Set qrydef = db.QueryDefs (QryName) 'Tutaj parametrowi nadajemy nazwę. Qrydef ("ID klienta") = CustID Set rs = qrydef.OpenRecordset() RunParamQuery = rs.RecordCount Rs.Close End Function Wykonywanie kwerendy poprzez zbiór parametrów Wydruk 4.17 wykorzystuje w kwerendzie zbiór parametrów. Umieszczając w argumentach funkcji słowo kluczowe ParamArray, możesz używać jej z różnymi kwerendami parametrycznymi, niezależnie od ilości wymaganych przez nie parametrów. Funkcja wykonuje pętlę poprzez tablicę ParamArgs() i przyznaje parametry w kolejności ich podawania. Aby użyć tej funkcji, uruchom ją z okna Analiza programu. Otrzymany rezultat to ilość rekordów. Kilkukrotne uruchomienie tej funkcji zaowocuje przyspieszeniem pracy kwerend parametrycznych. Wydruk 4.17. Funkcja uruchamiająca kwerendy parametryczne ze zmienną ilością parametrów Function OpenParamQuery (QryName, _ ParamArray ParamArgs() As Variant) As Long 'Z "Access 2000 – Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston 'Argumenty ' QryName – Nazwa kwerendy prametrycznej ' ParamArgs – Zmienna lista wartości wprowadzanych do ' parametrów kwerendy. Muszą być ' ułożone w takiej kolejności, w jakiej spodziewa się ich kwerenda. Dim db As Database Dim qrydef As QueryDef Dim i As Integer Dim rs As Recordset Dim rscount As Long On Erro GoTo OpenParameterQuery_Error Setdb = CurrentDb() Set qry = db.QueryDefs(QueryName) 'Przejdź przez wszystkie parametry I przyznawaj je według indeksów For i = 0 To Ubound(ParamArgs()) qry.Parameters(i) = ParamArgs(i) Next Set rs = qry.OpenRecordset(dbOpenSnapshot) OpenParameterQuery = rs.RecordCount OpenParamQuery_Exit: Set qry = Nothing rs.Close Exit Function OpenParamQuery_Error: OpenParamQuery = 0 GoTo OpenParamQuery_Exit End Function Jeśli dokonasz parametryzacji zagnieżdżonej kwerendy, wciąż będzie istniał tylko jeden zbiór parametrów. Kwerendy przekazujące Access posiada umiejętność łączenia tabel z innych źródeł danych i tworzenia opartych na nich kwerend tak, jakby były utworzone w Accessie. Oprócz tego, Access może również przesyłać kwerendy do innych baz danych. W takiej sytuacji, obca baza sama przetwarza swoje dane i zwraca jedynie zestaw rezultatów. Głównymi przyczynami, dla których warto używać kwerend przekazujących, są: wydajność i przepustowość sieci. Gdy dołączasz tabelę z bazy typu klient-serwer (np. SQL Server lub Oracle) i uruchamiasz kwerendę opartą na tej tabeli, serwer nie jest w stanie stwierdzić, czego od niego oczekujesz. Nawet, gdyby serwer mógł zobaczyć procedurę SQL Accessa, nie mógłby jej zinterpretować, gdyż jest napisana w innym dialekcie SQL niż ten używany przez serwery. Wówczas serwer może tylko przesłać olbrzymie ilości informacji na komputer klienta i pozostawić wszystkie obliczenia silnikowi Jet. W przypadku dużych baz operacja taka może spowolnić działanie sieci i w żadnym wypadku nie można jej nazwać efektywnym korzystaniem z serwera. Zamiast tego, możesz, korzystając z kwerendy przekazującej, „spotkać” serwer w pół drogi. Kwerenda przekazująca jest jedną z kwerend charakterystycznych dla języka SQL, co oznacza, że będziesz musiał ją napisać w SQL. A tak właściwie, to w dialekcie SQL serwera. Wiele opcji, z których możesz korzystać w Accessie, nie jest dostępnych w kwerendach przekazujących. Jednakże wzrost prędkości i zmniejszenie obciążenia sieci zrekompensują to z nawiązką. Tworzenie kwerendy przekazującej Kwerenda przekazująca tworzona jest tak jak każda inna kwerenda, z tą różnicą, że nie dodaje się do niej żadnych tabel. Po jej utworzeniu z menu Kwerenda wybierz opcję Wyłącznie SQL, a następnie Przekazująca. Spowoduje to zamianę okna Kwerenda w okno SQL. Istnieją tylko dwie właściwości, ważne dla uruchamiania kwerendy przekazującej: sama procedura SQL i ciąg połączenia. Procedura SQL zawiera polecenia dla serwera we właściwej, zrozumiałej dla niego składni SQL. Ciąg połączenia zawiera informacje niezbędne, by kwerenda mogła skontaktować się z serwerem. Oto przykład możliwego ciągu połączenia: ODBC; DRIVER=SQL SERVER; SERVER=Access2000UnleashedServer; UID=sa; DATABASE=PUBS; TRUSTED_CONNECTION=YES ODBC (Open Database Connectivity) to przedrostek ciągu połączenia. Poprzedza on zawsze ciągi połączenia do baz danych SQL Server, Oracle, Informix i Sybase. Każde źródło danych ODBC używa sterownika, aby tłumaczyć polecenia ODBC. Nazwa zazwyczaj przypomina nazwę oprogramowania serwera. Server to właściwy adres, pod którym znajduje się baza danych. UID (User ID) informuje serwer, kim jesteś. W ciągu połączenia może być również przechowywane hasło, jednakże nie jest to zalecane. Na jednym serwerze może znajdować się wiele baz danych. Warunek Database wskazuje kwerendzie odpowiednią bazę. Trusted Connection umożliwia dostanie się do serwera, jeśli masz na nim utworzony profil, któremu serwer „ufa”. Jeśli nie jesteś pewien, jak ciąg połączenia powinien wyglądać, skontaktuj się z administratorem bazy danych lub skopiuj ciąg połączenia z dołączonej tabeli. Następnie wklej go do właściwości ciągu połączenia kwerendy i zmodyfikuj opisane wcześniej właściwości. Po ustawieniu właściwości możesz wprowadzić wyrażenie SQL o składni właściwej dla serwera, do którego adresowana będzie kwerenda. Oto przykład prostego wyrażenia SQL dla bazy SQL Server. Rezultat przedstawiony jest na rysunku 4.20. Select * from klienci Where Kraj = 'USA' Rysunek 4.20. Wynik kwerendy przekazującej SQL Teraz siecią przesyłany jest jedynie zestaw rezultatów, ponieważ całą pracę wykonał serwer. Następnym krokiem jest stworzenie widoków i procedur przechowywanych na serwerze. Procedury przechowywane na serwerze mogą być uruchamiane z poziomu kwerendy przekazującej, poprzez podanie ich nazw i wszystkich wymaganych parametrów. Dodatkową zaletą tego sposobu jest to, iż serwer może polegać na własnych zdolnościach optymalizacyjnych i profilach wykonania, aby uzyskać jeszcze większą wydajność. Kwerendy definiujące dane Poza umiejętnością manipulowania danym zawartymi w tabelach kwerendy Accessa mogą również tworzyć, modyfikować i usuwać tabele w Accessie w taki sposób, by nadać aplikacji umiejętność inteligentnej pracy z danymi. Kwerendy definiujące dane mogą działać na tabelach Jet, lecz nie tylko. Jeśli zajdzie potrzeba definiowania danych w tabelach nie utworzonych przez mechanizm Jet, zadziałać mogą obiekty DAO. Jeśli musisz definiować dane w tabelach baz SQL Server lub Oracle, możesz skorzystać z podobnych opcji w ich językach SQL. Wykonuj ich definiujące dane procedury SQL poprzez kwerendy przekazujące Accessa. Kwerendy definiujące dane dokonują ciągłych modyfikacji w liczbie, strukturze i właściwościach tabel, indeksów i relacji. Zanim zaczniesz z nimi pracować, sporządź kopię zapasową swojej bazy i uruchom je w kopii swojego projektu. Kwerendy definiujące dane posiadają podstawowy schemat, którego zrozumienie znacznie ułatwia korzystanie z nich. Zaczynają się słowem kluczowym Create Table, Alter Table lub Drop Table, po którym występuje nazwa tabeli. Kolejnym elementem jest umieszczona w nawiasie sekcja definiująca pole. Po niej występuje nazwa pola, jego typ danych, a następnie rozmiar pola (w nawiasie). Sekcja definiująca dane może być dowolnej długości. Po każdej definicji pola może występować warunek ograniczający, ustawiający indeksy, klucze i klucze: obcy lub nadający polu wartość NOT NULL. Warunek ograniczający jest opcjonalny. Tworzenie nowej tabeli Logicznym początkiem pracy z kwerendami definiującymi dane jest procedura Create Table. Jak sama nazwa wskazuje, będzie ona tworzyła tabelę, jednakże jej zdolności do tego się nie ograniczają. Korzystając z kwerendy tworzącej tabele, możesz utworzyć tabele z poziomu siatki QBE, jednakże ten sposób nie umożliwia określenia rozmiaru i ograniczeń pola, indeksów oraz relacji. Korzystając z procedur definiujących dane w kwerendzie charakterystycznej dla języka SQL, możesz tworzyć lub modyfikować tabele w taki sam sposób, jak dokonujesz zmian w tabeli w widoku Projekt. Składnia prostej procedury Create Table wygląda następująco: Create Table nazwatabeli (pole1 typdanych (rozmiar), pole2 typdanych (rozmiar),...,); Budować kwerendy można jedynie w oparciu o zamknięte w danym momencie tabele. Aby utworzyć tabelę zawierającą dwa pola o długości 15 znaków, możesz użyć następującej procedury: CREATE TABLE TestTable (FirstName TEXT (15), LastName TEXT (15)); Po uruchomieniu tej kwerendy i odświeżeniu zawartości bazy zauważysz nową tabelę. Będąc w widoku Projekt zauważysz również, że długość obu pól ustawiona jest na 15 znaków. Gdybyś użył tradycyjnej kwerendy tworzącej tabele, pola miałyby długość 255 znaków. Rozmiar pola jest opcjonalną częścią procedury. Gdyby go w niej nie umieścić, pola miałyby długość 255 znaków. Dobrze jest korzystać z tego polecenia, kiedy to tylko możliwe. Modyfikowanie tabeli Po utworzeniu tabeli możliwe jest modyfikowanie jej zawartości przy użyciu kwerend definiujących dane. Polecenie Alter Table powoduje dodanie pola do tabeli. Podstawowe polecenie Alter Table ma następującą składnię: ALTER TABLE nazwatabeli ADD nazwapola1 typdanych (rozmiar), nazwapola2 typdanych (rozmiar); Aby zmodyfikować tabelę, dodając do niej dwa nowe pola, możesz użyć następującego polecenia: Alter Table TestTable Add Phone Text (10), Fax Text (10), Cellular Text (10); Utworzone w ten sposób pola mogą być dalej określane za pomocą warunków ograniczających. Warunki te omówimy jednak osobno. Nowością w Accessie 2000 jest możliwość dodawania więcej niż jednego pola jednocześnie. Jednakże wciąż konieczne jest korzystanie z osobnych poleceń Drop do usuwania pól z tabeli. Alter Table TestTable drop Phone; I Alter Table TestTable drop Fax; I Alter Table TestTable drop Cellular; Tworzenie indeksów Po utworzeniu, zaimportowaniu bądź dołączeniu tabeli może zaistnieć konieczność utworzenia indeksu. Umożliwia to polecenie Create Index. Podstawowa składnia tego polecenia jest następująca: CREATE [UNIQUE] INDEX nazwaindeksu ON nazwatabeli (nazwapola1 ASC/DESC nazwapola2 ASC/DESC...) [WITH Primary/Disallow Null/Ignore Null] Jeśli indeks ma zawierać tylko wartości unikatowe, użyj słowa kluczowego UNIQUE. Warunek opcjonalny WITH umożliwia wymuszenie zasad poprawności. Indeks może zakazać użycia wartości Null poprzez użycie Disallow Null. Opcja Ignore Null dopuszcza rekordy z wartością Null w indeksowanym polu, jednakże usuwa je z indeksu. Gdy używane jest słowo kluczowe PRIMARY, może zastępować słowo UNIQUE. Poniższe wyrażenie utworzy indeks w nowej tabeli: Create Index Nazwisko on TabelaTestowa(Nazwisko) with primary; Zauważ, że dla polecenia CREATE INDEX składnia jest nieco inna. W tym przypadku nazwa pola poprzedza nazwę tabeli. Sprawdź w projekcie tabeli, aby potwierdzić utworzenie klucza podstawowego w polu Nazwisko. Możliwe jest tworzenie indeksów w tabelach połączonych ze źródłem danych ODBC, jeśli tabele te nie posiadają jeszcze indeksu. W tym przypadku, indeksy nie znajdują się na serwerze. Rezydują w Accessie jako dynamiczne odnośniki do pól z danymi. Serwer nie zauważa tych pseudoindeksów i nie są wymagane specjalne pozwolenia, aby je tworzyć. Aby tego dokonać, użyj tej samej składni jak dla tabel źródłowych. Pseudoindeksów używaj w przypadkach, gdy źródło ODBC nie posiada własnego indeksu, a użytkownicy muszą aktualizować dane. Usuwanie tabeli Aby usunąć tabelę z bazy danych lub usunąć indeks z tabeli, użyj polecenia DROP TABLE lub DROP INDEX. DROP TABLE nazwatabeli/[nazwaindeksu ON nazwatabeli] Poniższe wyrażenie usunie z bazy tabelę i wszystkie zawarte w niej dane: DROP TABEL TabelaTestowa Określanie właściwości pól Warunki ograniczające pozwalają na określenie pozostałych właściwości pól. Właściwości te można podzielić na dwie grupy: klucze i relacje. Warunki ograniczające umieszczane są w po definicji pola w wyrażeniu definiującym dane. W warunku nie jest stosowana interpunkcja, tak więc ważna jest kolejność. Gdy określamy klucze, składnia jest następująca: CONSTRAINT nazwawarunku PRIMARY KEY/UNIQUE/NOT NULL Gdy określamy relacje dla tabeli lub pola, składnia warunku ograniczającego jest nieco inna: CONSTRAINT nazwarelacji REFERENCES nazwainnejtabeli (nazwapowiązanegopola) Gdy tworzysz relacje między dwoma polami, za pomocą warunku CONSTRAINT, pamiętaj, że typy danych tych pól muszą być takie same lub kompatybilne. Znajdujące się na wydruku 4.18 wyrażenie definiujące dane tworzy tabelę z polem IDpracownika, o typie danych Long. Pole to jest kluczem głównym tabeli. Tworzy ona również relację między tym polem i polem Idpracownika w tabeli Pracownicy. Wyrażenie to tworzy jednocześnie pola Imię, Nazwisko i Telefon. Wydruk 4.18. Użycie warunków podczas tworzenia pól CREATE TABLE TabelaTestowa (IDpracownika Long CONSTRAINT myFieldConstraint PRIMARY KEY Constraint myRelations references Pracownicy (IDpracownika), Imię TEXT, Nazwisko TEXT, Telefon TEXT) Po uruchomieniu tej kwerendy otwórz okno Relacje i dodaj do niego tabelę TabelaTestowa. Access automatycznie rozpozna relację między tabelami Pracownicy i TabelaTestowa. Optymalizowanie kwerend Oto kilka czynności, które może wykonać programista, aby zapewnić odpowiednią wydajność kwerendy: ? Indeksuj sprzężone pola po obu stronach relacji. Dotyczy to również tabel nie tworzonych przez mechanizm Jet. ? Gdy pomiędzy dwoma tabelami istnieje więcej niż jedno pole sprzężone, ustaw pola w siatce kwerendy w taki sposób, w jaki występują w swoich tabelach. ? Utwórz indeks dla pól, których będziesz używał do sortowania. Nieindeksowane pola sortuj tylko w ostateczności. ? Upewnij się, że dla wszystkich pól wybrałeś właściwy typ danych i rozmiar. Rozmiar pól powinien być możliwie najmniejszy. ? Nie przeciążaj siatki QBE. Używaj tylko pól niezbędnych dla zestawu rezultatów. ? Nie umieszczaj pól obliczanych w zagnieżdżonej kwerendzie. Zamiast tego, obliczenia wykonuj na końcu sekwencji kwerend lub, jeśli to tylko możliwe, na formularzu i raporcie. ? Staraj się unikać korzystania z pól Grupuj według. Pola te zabierają dużo miejsca i mogą niekorzystnie wpływać na wydajność. Jeśli pogrupowane pola mają indeksy, spróbuj używać ich w takiej samej kolejności, w jakiej występują w tabeli. ? Kwerenda podsumowująca ze sprzężeniami może być bardziej wydajna po podzieleniu jej na dwie osobne kwerendy. Pierwsza z nich wykonuje sprzężenie, a kwerenda grupująca korzysta z zestawu rezultatów pierwszej. ? Umieszczenie kryteriów po jednej zamiast po drugiej stronie relacji może mieć również wpływ na wydajność. Zazwyczaj kwerenda z kryterium po stronie Jeden relacji jest szybsza, lecz eksperymentowanie może dać inne wyniki. ? Formularze i Raporty zawsze działają szybciej, gdy są oparte na tabeli. Gdy to tylko możliwe, z zestawu rezultatów twórz tabelę, na której będziesz opierał formularze i raporty. ? Kwerendy krzyżowe działają szybciej, gdy w nagłówku kolumny nie umieszczono żadnych obliczeń. Mimo iż obliczenia te są czasami konieczne dla podsumowań, unikaj umieszczania ich jedynie ze względów kosmetycznych. ? Używaj kwerend parametrycznych poprzez kod zamiast ciągów SQL w kodzie. Ponieważ kwerendy parametryczne są obiektami kompilowanymi i mają profil wykonania, zazwyczaj będą działać szybciej niż odpowiadający im ciąg SQL. Gdy tylko to możliwe, korzystaj z techniki Accessa 2000 klient-serwer. Rozdział 5. Jet 4.0 – silnik baz danych Microsoft W tym rozdziale: ? Historia Microsoft Jet. ? Praktyczne zastosowanie nowych opcji silnika Jet 4.0. Access 2000 jest zaawansowanym interfejsem użytkownika dla silnika baz danych Microsoft Jet 4.0. Niezależnie od tego, czy jesteś tego świadom, Jet zarządza bazą danych zawartą w pliku MDB. Gdy uruchamiasz plik typu MDB poprzez obiekty DAO lub ADO, również używasz do tego silnika Microsoft Jet. Przechowuje on tabele, indeksy i kwerendy, które uruchamia poprzez wbudowany mechanizm zapytań. Jet jest rozbudowaną, wyposażoną w kompletny zestaw funkcji, wielowątkową, relacyjną bazą danych. Historia Microsoft Jet Dzisiaj Microsoft Jet używany jest jako aparat bazy danych w ponad 30 produktach firmy Microsoft. Można wśród nich wymienić (oprócz, rzecz jasna, Accessa) takie programy, jak Project, Money, Team Manager, a nawet edukacyjne gry dla dzieci. Jet całkowicie zdominował rynek domowych baz danych, gdyż każda jego edycja zawiera coraz nowocześniejsze technologie. Cofnijmy się teraz odrobinę, aby prześledzić historię Microsoft Jet. Jet 1.0 Historia Microsoft Jet rozpoczyna się ponad dziesięć lat temu, kiedy to w firmie Microsoft rozpoczęto wdrażanie projektu Access. Gdy w 1992 roku Access 1.0 trafił na półki sklepowe, razem z nim na rynek domowych baz danych wszedł Jet 1.0. Zawierał on wiele bardzo potrzebnych opcji domowych baz danych, jak definiowanie danych, kwe- rendy, zabezpieczenia i indeksowanie. Jet był jednocześnie produktem pionierskim, gdyż zawierał wiele nowych opcji, jak na przykład: kwerendy aktualizujące, heterogeniczne sprzężenia danych i możliwość tworzenia kwerendy w oparciu o inną kwerendę. Opcje te umożliwiły programowi Microsoft Access osiągnąć pozycję najpopularniejszej domowej bazy danych. Jet 1.1 Sukces Accessa był zaskoczeniem dla wszystkich, łącznie z firmą Microsoft. W maju 1993 roku wydano Access 1.1 oraz Visual Basic 3.0, a razem z nimi Jet 1.1. Ta edycja umożliwiała programistom korzystanie z wielu nowych opcji: poprawionej, zgodnej ze standardem ODBC komunikacji i nowych sterowników ODBC. Od tej pory zaprzestano tworzenia kodu programu poprzez interfejs API ODBC, a dostęp do danych ODBC stał się możliwy dla każdego. Jet 1.1 umożliwił również swoim użytkownikom łatwe dołączanie zewnętrznych danych, zwłaszcza w nowym formacie Microsoft FoxPro. Poprawiono biblioteki obiektów DAO, a maksymalny rozmiar bazy Jet wzrósł ze 128 MB do 1,1 GB. Jet 2.0 Jet 2.0 został wprowadzony na rynek w kwietniu 1994 roku wraz z bardzo popularnym Accessem 2.0. Dzięki takim opcjom jak wymuszanie reguł poprawności na poziomie silnika bazy, czy integralności referencyjnej Jet 2.0 stał się nowoczesnym aparatem baz danych. Aby zwiększyć jego wydajność, dodano również zapożyczoną z FOX-a technologię Rushmore oraz poprawiono funkcjonowanie SQL i obiektów DAO. Jet 2.0 był również, bardziej niż poprzednie wersje, zgodny z ANSI. Jet 2.5 W październiku 1994 roku firma Microsoft wypuściła na rynek pakiet Service Pack do Accessa 2.0 oraz pakiet sterowników ODBC Desktop Drivers Pack 2.0. Były to również narodziny Jet 2.5. W tej wersji do konstruowania wyrażeń Jet używał już VBA, a wsparcie dla źródeł danych ODBC uległo znacznej poprawie. Ulepszono także obsługę aplikacji przeznaczonych dla wielu użytkowników. Jet 3.0 Gdy pod koniec 1995 roku Microsoft wypuścił na rynek Access 95, silnik Jet został wprowadzony w 32-bitowe środowisko. Jet stał się zatem 32-bitowym silnikiem baz danych, posiadającym zdolność replikacji danych, a także ulepszone opcje ODBC i DAO. Jet 3.0 był bardzo szybkim silnikiem baz danych. Jet 3.5 Wraz z wprowadzeniem na rynek w styczniu 1997 roku pakietu Office 97 oddano do rąk użytkowników Jet 3.5. Był on już w pełni 32-bitowym silnikiem baz danych, którego największym ulepszeniem był znaczny wzrost wydajności. Jet 3.5 zawierał także nowe zdolności buforowania danych, poprawione blokowanie stron, ulepszenia w pracy kwerend, ODBCDirect oraz programowe anulowanie poleceń zapisu na dysk. Replikacja została rozszerzona o repliki częściowe, a wsparcie danych zewnętrznych o obsługę danych HTML i Exchange. Jet 3.51 Wypuszczenie na rynek w połowie 1997 roku Jet 3.51, będącego kontynuacją Jet 3.5, prawie nie zostało zauważone. Nowy Jet zawierał ulepszoną metodę defragmentowania i naprawiania plików typu MDB. Opcja naprawiania została włączona w znacznie poprawiony proces defragmentowania. W Jet 3.51 poprawiono błędy dotyczące niskopoziomowej obsługi wielu użytkowników, jednakże najważniejsze w nim było narzędzie do defragmentowania i naprawy JetCOMP.exe, korzystające z nowej opcji defragmentującej. Jet 4.0 W czerwcu 1999 roku, wraz z pakietem Office 2000, Microsoft wypuścił na rynek Jet 4.0. Edycja ta była tym, na co czekali wszyscy programiści. Jet 4.0 zawiera więcej funkcji niż wszystkie poprzednie wersje razem wzięte. Większość z nich została dodana dzięki uwzględnieniu zgromadzonych przez lata próśb i uwag programistów. Wersja 4.0 to bardzo rozbudowany program, zawierający tak zaawansowane opcje, jak: ? nowy wbudowany dostawca baz danych OLE; ? blokowanie na poziomie rekordów; ? pełna obsługa Unicode; ? ulepszone typy danych; ? poprawione funkcje Autonumerowania; ? przeszukiwalne pola typu Memo; ? poprawki trybu przeznaczonego dla wielu użytkowników; ? ulepszenia w replikacji; ? nowa składnia SQL (bardziej zgodna z ANSI 92). Gdy poznasz te opcje i będziesz przy ich użyciu budował aplikacje, z trudem będziesz mógł sobie wyobrazić, jak wyglądała Twoja praca, gdy tych opcji nie było. Przyszłe wersje Microsoft Jet Na początku 1998 roku pojawiły się plotki, że era Jet ma się ku końcowi. Wraz z pakietem Office 2000 Microsoft wydał „domową” wersję SQL Server 7.0 i typ projektów Accessa, który był alternatywą dla Jet (ADP – patrz rozdział 15. „Wprowadzenie do projektów programu Microsoft Access oraz narzędzi wizualnych”). Wraz z obiektami ADO 2.0 i Universal Data Access, Microsoft wypuścił bazy danych OLE jako metodę dostępu do danych w architekturze klient-serwer (więcej informacji o bazach danych OLE i obiektach ADO w rozdziale 6. „Wprowadzenie do obiektów danych ActiveX” i 7. „Zaawansowane ADO”). ADO 2.0 i bazy danych OLE porozumiewają się ze źródłem danych bezpośrednio poprzez OLE. Ponieważ Microsoft chciał korzystać z baz OLE dla architektury klient-serwer poprzez ADP, klienci uznali, że to już koniec Jet. Microsoft zaprzeczył tym plotkom na wielu konferencjach prasowych i zapewnił, że silnik Jet będzie nadal umieszczany w produktach tej firmy. Praktyczne zastosowanie nowych opcji silnika Jet 4.0 W rozdziale tym omówimy zaawansowane opcje silnika baz danych Microsoft Jet 4.0. Wszystkie przykłady kodu działają w Accessie 2000, a po dokonaniu drobnych modyfikacji w Visual Basic 5 lub 6. Wbudowany dostawca baz danych OLE Jeśli jeszcze tego nie wiesz, strategia dostępu do danych Microsoftu opiera się aktualnie na obiektach ActiveX Data Objects (ADO) (więcej informacji o obiektach ADO w rozdziale 6. „Wprowadzenie do obiektów danych ActiveX” i 7. „Zaawansowane ADO”). Działanie obiektów ADO oparte jest na koncepcji powszechnego dostępu do danych, wykorzystującego do komunikowania się ze źródłami danych wbudowanych dostawców. ADO 1.0 zawierało losowego dostawcę dla ODBC, tak więc gdybyś używał Jet i ADO, byłbyś zmuszony do korzystania z warstwy ODBC. Jet 4.0 posiada wbudowanego dostawcę baz danych OLE o nazwie kodowej JOLT 4.0. Umożliwia Ci to wykorzystywanie ADO jako metodologii dostępu do danych w aparacie Jet. Poprzez JOLT masz dostęp do zestawu funkcji Jet, a ponadto do kilku opcji charakterystycznych dla JOLT. Temat ten będzie poruszany jeszcze kilkakrotnie w dalszej części tej książki. Blokowanie na poziomie rekordu Tak, nie pomyliłeś się! Jet 4.0 obsługuje blokowanie na poziomie rekordu! Teraz możesz poprawić współbieżność aplikacji, blokując jeden wiersz, a nie jak to miało miejsce wcześniej – całą stronę. Blokowanie na poziomie rekordu może wpłynąć na znaczne zwiększenie wydajności obszernych, transakcyjnych baz danych. W niektórych testach, blokowanie na poziomie rekordu umożliwiło sześciokrotną poprawę wydajności w stosunku do blokowania na poziomie strony. Programowa obsługa blokowania na poziomie rekordu będzie dostępna w ADO i Accessie, ale nie w DAO. Bezpośrednią korzyścią z blokowania na poziomie rekordu jest koniec konfliktów z blokowaniem stron. Więcej na temat blokowania na poziomie wiersza w rozdziale 21. „Zagadnienia wielodostępu, serwer plików, blokowanie”. Pełna obsługa Unicode Jet 4.0 przechowuje wszystkie dane o znakach (wszystkie pola typu Tekst i Memo) w kodzie Unicode. Umożliwia to łatwe przełączanie się pomiędzy językami i zestawami znaków w aplikacji. Teraz, gdy konwertujesz coś na inny język lub alfabet, masz 100% gwarancji zgodności danych po konwersji. Czym jest Unicode? Dzisiaj na świecie istnieje wiele nakładających się na siebie standardów kodowania znaków tekstowych. W przypadku istnienia tak wielu różnych zestawów znaków dla stron kodowych proces tworzenia jednego, międzynarodowego kodu podstawowego jest wyjątkowo trudny. Mniej więcej dziesięć lat temu firmy Apple i Xerox zaczęły wspólnie opracowywać nowy standard zestawu znaków. W 1991 roku firmy te założyły konsorcjum Unicode. Obecnie jego członkami są między innymi: Microsoft, Apple, AT&T, Compaq, Digital, Ecological Linguistics, Hewlett-Packard, IBM, Lotus, NeXT, Novell, Reuters oraz wiele innych firm. Na początku lat dziewięćdziesiątych International Standards Organisation (ISO), w połączeniu z konsorcjum Unicode, rozpoczęła prace nad podobnym standardem. Dzięki tej współpracy wydane w 1993 roku Unicode 1.1 i ISO 10646 są identyczne. Do przedstawiania znaków tekstowych ze wszystkich języków poza chińskim kod Unicode korzysta z 16-bitowego schematu kodowania znaków o stałej szerokości. Kod Unicode rozwiązuje problem dużej liczby języków stron kodowych i umożliwia wymianę i współdzielenie danych między wieloma językami bez ryzyka uszkodzenia. Obsługa Unicode 1.1 w silniku Jet 4.0 Aby umieścić kod Unicode w silniku Jet 4.0, rozmiar strony danych został zwiększony do 4 KB. Umożliwiło to zmianę ograniczenia wielkości pliku typu MDB z 1,07 GB do 2,14 GB. Ponieważ Unicode przechowuje dane w większych stronach, rozmiar niektórych baz (z dużą ilością danych tekstowych) może się zwiększyć. Jednakże Jet umożliwia kompresję kodu Unicode. Opcja Kompresja Unicode jest również dostępna podczas projektowania tabel w Accessie (rysunek 5.1). Rysunek 5.1. Opcja Kompresja Unicode w tabeli w widoku Projekt Kompresja indeksu jest domyślnie włączona i jeśli konwertujesz aplikację z poprzedniego formatu pliku, wszystkie typy znaków będą miały włączoną opcję Kompresja Unicode. Jeśli jednak baza danych jest już w formacie pliku Jet 4.0, aby włączyć kompresję Unicode, właściwość ta musi zostać ustawiona. Kompresja Unicode nie działa na polach typu Memo o rozmiarze przekraczającym 4 kB, posiadających na stronie inne wiersze. Aby przy użyciu SQL określić kolumnę, która będzie używać kompresji, podczas tworzenia tabeli z DDL użyj nowego znacznika WITH COMPRESSION: CREATE TABLE MyTable (MyCompressedField CHARACTER (255) WITH COMPRESSION) Ta klauzula SQL dostępna jest jedynie poprzez kod VBA i ADO. Powyższe wyrażenie SQL możesz wykonać poprzez aktualne połączenie ADO projektu VBA (wydruk 5.1). Wydruk 5.1. Tworzenie skompresowanego pola Unicode w VBA Private Sub cmdUnicode_Click() 'Procedura ta spowoduje utworzenie tabeli MyTable i 'skompresowanego pola w standardzie Unicode o nazwie MyCoolCounter 'Kod ten może być uruchamiany jedynie poprzez ADO w VBA 'i nie jest obsługiwany przez DAO 'Z książki "Access 2000 Księga Eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim strSQL As String On Error GoTo Proc_Err 'Utwórz procedurę SQL strSQL = "CREATE TABLE MyTable (MyCompressedField CHARACTER(255) WITH COMPRESSION)" 'Wykonaj procedurę SQL na 'aktualnym połączeniu ADO CurrentProject.Connection.Execute strSQL 'Sukces MsgBox "Tabela Utworzona OK", vbInformation Proc_Exit: Exit Sub Proc_Err: 'Określ, czy tabela istnieje If Err.Number = -2147217900 Then MsgBox "Obiekt już istnieje. Usuń go i spróbuj jeszcze raz",_ vbCritical Else MsgBox Err.Description, vbCritical End If Resume Proc_Exit End Sub Sortowanie kompatybilne z NT Umieszczenie kodu Unicode w silniku Jet 4.0 umożliwiło mu korzystanie z mechanizmu sortowania opartego na zestawie funkcji Microsoft Windows NT. Ten nowy mechanizm sortujący używany jest przez Jet również w systemach Windows 95 i 98. W systemach tych możliwe jest również właściwe sortowanie wszystkich dostępnych w Windows NT języków, zamiast jedynie domyślnego języka systemu, który Windows 95 obsługuje w swoim sortowaniu ANSI. Pozwala to szybciej i łatwiej tworzyć międzynarodowe aplikacje, ponieważ teraz działa jednolite sortowanie we wszystkich systemach operacyjnych. Microsoft SQL Server 7.0 i Visual Basic 6 używają do sortowania tego samego zestawu funkcji, czego rezultatem jest jednolitość między produktami. Typy danych Jet Tabela 5.1 zawiera przegląd typów danych Jet. Typy danych w silniku Jet 4.0 zostały poprawione, aby lepiej współpracować z SQL Server. Aby ułatwić przenoszenie i replikowanie baz danych Jet do SQL Server, typy danych zostały do siebie upodobnione. Nazwy typów danych Jet nie zawsze są takie same jak w Accessie. Access tłumaczy je za Ciebie. Tabela 5.1. Przegląd typów danych Jet 4.0 Typ danych Jet Nazwa w Accessie Uwagi Character Tekst Maksymalna długość to 255 znaków. Dzięki obsłudze Unicode długość ta dotyczy wszystkich języków. Dopuszczalne synonimy: Char, Varchar, Character Varying, Nchar, National Character, National Char, Nvarchar, National Character Varying i National Char Varying. Tabela 5.1. Przegląd typów danych Jet 4.0 (ciąg dalszy) Typ danych Jet Nazwa w Accessie Uwagi Użycie słowa Tekst bez określenia długości ma teraz inne znaczenie. Jest synonimem dla Memo. To przybliża znaczenie słowa Tekst silnika Jet do jego znaczenia w Microsoft SQL Server. Możesz wciąż używać słowa Tekst z określeniem długości, na przykład TEKST (100), aby określić stałą ilość znaków w kolumnie. Poniższy przykład ilustruje użycie TEKST do określania typu danych: CREATE TABLE t1 (c1 TEXT) oznacza to samo, co CREATE TABLE t1 (c1 MEMO) i zbliżone jest do definicji i składni słowa TEXT w SQL Server. CREATE TABLE t1 (c1 TEXT (100)) oznacza to samo co CREATE TABLE t1 (c1 CHAR (100)) i zapewnia kompatybilność z większością już istniejących aplikacji Microsoft Jet. LongText Memo Maksymalna długość (w bajtach) wynosi teraz około 2.14 GB, czyli w przybliżeniu 1.07 miliarda znaków. Dopuszczalne synonimy to Text, Ntext, Memo, LongChar i Note. Binary Obiekt OLE Maksymalna długość to 255 znaków. Dopuszczalne synonimy: Varbinary, Binary, Varying oraz Bir Varying. LongBinary Obiekt OLE Maksymalna długość wynosi teraz około 2,14 GB. DateTime Data/Godzina Synonim Timestamp nie jest już akceptowany, a słowo Timestamp w SQL Server nie odpowiada dokładnie znaczeniu typu danych Data/Godzina. Single Pojedyncza precyzja Dopuszczalne synonimy: Real, Float4 oraz IEEESingle. Double Podwójna precyzja Dopuszczalne synonimy to Float, Double Precision, Float8 i IEEEDouble. Synonim Numeric nie jest już akceptowany dla tego typu danych. Słowo Numeric używane jest do zdefiniowania kolumny jako określonego typu danych, odpowiadającego typom danych Decimal bądź Numeric w SQL Server. Byte Bajt Jedyny dopuszczalny synonim to Tinyint. Integer Liczba całkowita Dopuszczalne synonimy: Smallint, Integer2 oraz Short. LongInteger Liczba całkowita długa Dopuszczalne synonimy: Int, Integer oraz Counter. Nie jest już akceptowane słowo AutoIncrement. Więcej informacji na ten temat znajdziesz w części o autoinkrementacji kolumn. Tabela 5.1. Przegląd typów danych Jet 4.0 (ciąg dalszy) Typ danych Jet Nazwa w Accessie Uwagi Currency Walutowy Dopuszczalny synonim to Money. Dane otrzymywane poprzez ODBC w formacie SQL_DECIMAL lub SQL_NUMERIC (na przykład: SQL Server Decimal lub Numeric) są kojarzone z typem danych Walutowy aparatu Jet. Boolean Tak/Nie[RG1] Dopuszczalne synonimy: Bit, Logical, Logical1 oraz YesNo. GUID IDreplikacji Jedyny dopuszczalny synonim to UniqueIdentifier. Decimal Dziesiętne Typ danych Dziesiętne jest nowością w aparacie Microsoft Jet 4.0. Jest to dokładny typ danych, przyjmujący wartości z zakresu 1028-1 do –1028-1. Możesz zdefiniować zarówno precyzję (1-28) i skalę (0 – zdefiniowana precyzja). Domyślne ustawienia precyzji i skali to odpowiednio 18 i 0. Dopuszczalne synonimy to Dec i Numeric. Dane otrzymywane poprzez ODBC w formacie SQL_DECIMAL lub SQL_NUMERIC będą teraz kojarzone z typem danych Dziesiętne aparatu Jet, a nie Walutowy. Zauważ, że ten typ danych obsługiwany jest jedynie przez ADO. Ulepszenia opcji Autonumerowanie Jet 4.0 daje pełną kontrolę nad polem typu Autonumerowanie. Masz teraz możliwość określenia punktu początkowego i przedziału licznika. Możesz sprawić, by pole Autonumerowanie zaczynało się od 1000 i przyrastało o 100. Te funkcje dostępne są jedynie poprzez SQL DDL do ADO/JOLT. Korzyścią, jaką dzięki temu otrzymujemy, jest większa kontrola nad sekwencjami klucza podstawowego. Aby utworzyć tabelę o nazwie MyCoolCounter z Autonumerowaniem rozpoczynającym się od 1000 i przyrastającym o 100 w polu CoolCounter użyj następującej składni SQL: CREATE TABLE MyCoolCounter (CoolCounter IDENTITY (1000,100), myTextField CHAR) Aby w dowolnym momencie modyfikować wartość początkową i przyrost, użyj polecenia ALTER TABLE. Przykładowo, by zmienić punkt początkowy na 5000, a przyrost na 10, składnia jest następująca: ALTER TABLE MyCoolCounter ALTER COLUMN CoolCounter IDENTITY (5000,10) Możesz zawsze odnaleźć ostatnią wstawioną wartość, korzystając z polecenia SELECT @@IDENTITY. Inaczej będzie zachowywać się baza w przypadku użycia wartości przyrostowych innych niż jeden. Jeśli wartość przyrostu jest inna niż jeden, Jet nie zresetuje następnej wartości do maksymalnej dopuszczalnej wartości w tabeli. Podobnie jak w poprzednich wersjach Jet domyślne ustawienie uniemożliwia użytkownikom edycję danych typu Licznik. Jednakże administratorzy będą mieli możliwość nadania użytkownikom praw, umożliwiających im aktualizowanie danych typu Licznik. Przeszukiwalne pola Memo W poprzednich wersjach Accessa i Jet pola typu Memo nie mogły być indeksowane. W silniku Jet 4.0 indeksowaniu podlega pierwszych 255 znaków. Podczas przeszukiwania z użyciem znaków zastępczych (*) używany jest jedynie indeks. Mimo iż funkcja ta działa poprawnie, ogranicza przeszukiwanie do pierwszych 255 znaków. Bierz to pod uwagę podczas przeszukiwania pól Memo, bo jeśli kryterium, według którego przeszukujesz, nie mieści się w tym zakresie, przeszukiwanie nie da właściwych rezultatów. Kontrola połączeń i zamknięcie bierne Wśród innych opcji związanych z obsługa wielu użytkowników należy wymienić nową Listę użytkowników, wyliczającą wszystkich użytkowników bazy poprzez ADO, jak miało to miejsce w przypadku narzędzia LDBView. Opcja Kontrola połączeń umożliwi Ci odmówienie dostępu do bazy. Mimo iż nie możesz „wyrzucić” innego użytkownika, możesz zabezpieczyć się przed podłączaniem się do bazy nowych użytkowników. Opcja ta, wraz z zestawem funkcji Listy użytkowników, pozwala biernie zamknąć bazę danych, a następnie, gdy wszyscy inni użytkownicy są odłączeni, otworzyć bazę z wyłącznością. Znajdujący się na wydruku 5.2 kod programu przedstawia użycie Listy użytkowników z biernym zamknięciem. Wydruk 5.2. Użycie Listy użytkowników w ADO Sub UserRoster(strPath As String) Dim conn As ADODB.Connection Dim rst As ADODB.Recordset Set conn = New ADODB.Connection With conn .Provider = "Microsoft.Jet.OLEDB.4.0" .ConnectionString = "data source=" & strPath .Open End With Set rst = conn.OpenSchema(adSchemaProviderSpecific, , _ "{947bb102-5d43-11d1-bdbf-00c04fb92675}") Do Until rst.EOF Debug.Print rst!COMPUTER_NAME Debug.Print rst!LOGIN_NAME Debug.Print rst!CONNECTED Debug.Print rst!SUSPECTED_STATE rst.MoveNext Loop End Sub Otwieramy połączenie ADO do bazy danych, a następnie ustawiamy właściwość obiektu Jet OLEDB.Connection na 1. Tak długo, jak obiekt połączenia ma wyznaczony zakres, żaden nowy użytkownik nie zostanie podłączony do bazy. Program znajdujący się na wydruku 5.2 otwiera jednocześnie listę użytkowników jako zestaw rekordów ADO. Aby otworzyć listę użytkowników, używamy metody połączenia z obiektem OpenSchema. Wymaga to przekazanie dość długiego identyfikatora GUID dla obiektu ADO w celu wskazania Listy użytkowników. W ten sposób otrzymamy zestaw rekordów z nazwą komputera, użytkownika (poprzez Jet Security lub Admin (przy braku zabezpieczeń), polem Connected, wskazującym czy dany użytkownik jest połączony z bazą, oraz polem Suspected_State, stwierdzającym, czy istnieje podejrzenie uszkodzenia bazy. Nowa składnia SQL Do Jet 4.0 dodano wiele rozszerzeń SQL, aby mógł on obsługiwać nowy zestaw funkcji i był bardziej zgodny z ANSI 92 SQL. Dodatkową korzyścią jest fakt, iż większość z tych rozszerzeń ułatwia pisanie wyrażeń SQL funkcjonujących między Jet a SQL Server. Ulepszenia SQL obejmują: ? Zabezpieczenia. ? Definiowanie widoków i procedur. ? Wywoływanie parametrów. ? Transakcje. ? Tworzenie i modyfikację tabel DDL. Zabezpieczenia Dzięki nowej składni, SQL obsługuje definiowanie zabezpieczeń bazy danych. Bezpośrednią z tego korzyścią jest ułatwienie programowej obsługi zabezpieczeń. Możesz teraz zrezygnować z ADO i DAO na korzyść SQL, aby zaspokajać swoje potrzeby w zakresie bezpieczeństwa. Poniższe wydruki zawierają rozszerzenia SQL obsługujące zabezpieczenia w Jet 4.0: CREATE/ADD/ALTER/DROP USER/GROUP GRANT/REVOKE Zabezpieczenia mogą być stosowane na poziomie następujących obiektów: CONTAINER (kontener), INDEX (indeks), QUERY (kwerenda) i TABLE (tabela). Procedura na wydruku 5.3 przedstawia jak utworzyć na tabeli tblCustomers posiadającej pełne uprawnienia grupę o nazwie SuperGroup. Następnie kod spowoduje odebranie tej grupie pozwolenia usuwania danych z tabeli tblCustomers, po czym utworzy użytkownika o imieniu Steve i haśle Batman, aby na końcu dodać go do grupy SuperGroup. Wydruk 5.3. Ustawianie zabezpieczeń w Jet 4.0 Private Sub cmdSecurity_Click() 'Procedura ta spowoduje otwarcie pliku MDB z określonym plikiem 'zabezpieczeń, ?a następnie dodanie użytkowników i grup 'Kod ten może być uruchamiany jedynie poprzez ADO w VBA 'i nie jest obsługiwany przez DAO 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection On Error GoTo Proc_Err Set conn = New ADODB.Connection 'Ustaw połączenie do bazy danych 'używając ADO i określając w ciągu połączenia bazę systemową With conn .Provider = "Microsoft.Jet.OLEDB.4.0" .ConnectionString = "data source=" & strPath & _ ";Jet OLEDB:System database=" & strMDWPath .Open End With 'Wykonaj procedury SQL conn.Execute "CREATE GROUP SuperGroup" conn.Execute "GRANT SELECT, DELETE, INSERT, UPDATE ON tblCustomers TO ?SuperGroup" conn.Execute "REVOKE DELETE ON tblCustomers From SuperGroup" conn.Execute "CREATE USER Steve Batman" conn.Execute "ADD USER Steve to SuperGroup" Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description, vbCritical Resume Proc_Exit End Sub Funkcje zabezpieczeń SQL w Jet 4.0 zostały również wyposażone w możliwość tworzenia bądź nadawania hasła w następujący sposób: ALTER DATABASE PASSWORD NewPass OldPass Definiowanie widoków i procedur Jet 4.0 umożliwia zdefiniowanie zapisanej kwerendy jako widok lub procedurę. Widok może być zdefiniowany jako nieparametryczna, zwracająca wiersze kwerenda. Procedurami nazywamy wszystkie nie korzystające z DDL i UNION czynności oraz kwerendy parametryczne. Widoki i procedury możesz tworzyć zarówno poprzez ADO, jak i nową składnię SQL Jet: CREATE VIEW i CREATE PROCEDURE. Nowa składnia jest bardziej kompatybilna z ANSI 92 i umożliwia łatwiejsze przenoszenie widoków i Jet do innych baz ANSI 92 SQL, jak na przykład SQL Server. Poniższy kod SQL tworzy widok i procedur. CREATE VIEW qryAllCustomers AS SELECT * FROM tblCustomers CREATE PROCEDURE qryAllCustomers_DEL AS DELETE * FROM tblCustomers Wywoływanie parametrów Poprzez ADO Jet 4.0 obsługuje teraz podawanie parametrów poprzez listę, co przypomina w działaniu wykonywanie zapisanej parametrycznej procedury SQL Server. Zapisana kwerenda qryParameterQuery posiada dwa parametry – EmployeeID i DepID: PARAMETERS [EmployeeID] Long, [DepID] Long; SELECT Employees.EmployeeID, Employees.[First Name], Employees.[Last Name], Employees.Phone, Employees.[Dept ID] FROM Employees WHERE (((Employees.EmployeeID)=[EmployeeID]) AND ((Employees.[Dept ID])=[DepID])); Podawanie parametrów i wykonywanie kwerendy parametrycznej jest teraz bardzo łatwe dzięki składni EXEC: EXEC qryParameterQuery 1, 4179 Ten kod SQL podaje następujące wartości parametrów: EmployeeID=1 i DepID=4179. Parametry musisz podawać w takiej kolejności, w jakiej znajdują się w kodzie SQL. Kod na wydruku 5.4 przedstawia, jak otwierać zestaw rekordów ADO oparty na kwerendzie qryParameterQuery. Wydruk 5.4. Otwieranie kwerendy parametrycznej w ADO Private Sub cmdPramQuery_Click() 'Procedura ta spowoduje otwarcie kwerendy parametrycznej 'przy użyciu nowej składni EXEC 'Kod ten może być uruchamiany jedynie poprzez ADO w VBA 'i nie jest obsługiwany przez DAO 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim rst As ADODB.Recordset On Error GoTo Proc_Err Set rst = New ADODB.Recordset 'Otwórz zestaw rekordów oparty na 'wykonywanej kwerendzie parametrycznej rst.Open "Exec qryParameterQuery 1", CurrentProject.Connection 'Display the results MsgBox rst![FirstName] Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description, vbCritical Resume Proc_Exit End Sub Transakcje SQL Jet 4.0 obsługuje teraz transakcje. Transakcja musi obowiązkowo rozpoczynać się w następujący sposób: BEGIN TRANSACTION Aby utworzyć lub cofnąć transakcję, użyj odpowiednio poniższych poleceń: ROLLBACK ROLLBACK TRANSACTION Kod na wydruku 5.5 przedstawia, w jaki sposób można edytować i usuwać rekordy w jednej transakcji. Zauważ, że transakcja musi rozpoczynać się w innej linii niż linia wyrażenia SQL. Wydruk 5.5. Transakcje w SQL Jet 4.0 Sub Jet40Transaction() Dim conn As ADODB.Connection Set conn = CurrentProject.Connection With conn .Provider = "Microsoft.Jet.OLEDB.4.0" .ConnectionString= "data source=" & Application.CurrentProject.Path & "employee_2k.mdb" .Open End With 'Execute the SQL Statements conn.Execute "BEGIN TRANSACTION" conn.Execute "UPDATE Employees SET Employees.HomePhone = " & _ Chr(39) & "2129560615" & Chr(39) & _ "WHERE (((Employees.EmployeeID)=1))" conn.Execute "DELETE" &vbNewLine & _ "From tasks" & vbNewLine & _ "WHERE (((Tasks.[Emp ID])=1)); " Conn.Execute "COMMIT TRANSACTION" End Sub Tworzenie tabel DDL W Microsoft Jet 4.0 polecenie CREATE TABLE jest znacznie potężniejsze. Najbardziej interesującą opcją nowych rozszerzeń SQL w silniku Jet 4.0 jest opcja CHECK CONSTRAINTS. Umożliwia ona rozszerzenie reguł biznesowych na więcej niż jedną tabelę. Możesz użyć SQL do odnalezienia informacji w kilku tabelach, a następnie użyć tych informacji do wymuszenia określonych warunków na nowo wstawianych rekordach. Załóżmy, że mamy tabele Customers (Klienci) i Credit Limit (Limit kredytu). Możesz nakazać silnikowi Jet wymuszenie reguły biznesowej, która spowoduje, że nowo wstawiany rekord może być zaakceptowany jedynie w sytuacji, gdy przyjmuje wartości niższe od przyjętego limitu kredytowego. Ograniczenie to zdefiniowałbyś poprzez SQL w następujący sposób: CHECK () Poniższy kod tworzy tabelę z ograniczeniem w polu CREDITLIMIT: CREATE TABLE Customers (CustId IDENTITY (100,10), CFrstNm VARCHAR(10), CLstNm VARCHAR(15), CustomerLimit DOUBLE, CHECK (CustomerLimit <= (SELECT SUM (CreditLimit) FROM CreditLimit))); Kod na wydruku 5.6 przedstawia, jak utworzyć tabelę CreditLimit, wprowadzić wartość, utworzyć tabelę Customers wraz z ograniczeniem, a następnie jak spróbować wstawiać wiersze. Pierwszy rekord zostanie zaakceptowany, a drugi będzie odrzucony ze względu na przekroczony limit kredytu. Wydruk 5.6. Użycie ograniczeń Private Sub cmdCreateConstraint_Click() 'Procedura ta spowoduje utworzenie 2 tabel, z których jedna 'będzie zawierać ograniczenie oparte na drugiej tabeli 'Kod ten może być uruchamiany jedynie poprzez ADO w VBA 'i nie jest obsługiwany przez DAO 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection On Error GoTo Proc_Err Set conn = CurrentProject.Connection 'Utwórz tabelę sprawdzającą limit kredytu conn.Execute "CREATE TABLE CreditLimit (CreditLimit DOUBLE);" 'Wprowadź limit kredytu conn.Execute "INSERT INTO CreditLimit VALUES (100);" 'Utwórz tabelę Customers (Klienci) z ograniczeniem conn.Execute "CREATE TABLE Customers_Con (CustId IDENTITY (100,"&_ " 10), CFrstNm VARCHAR(10), CLstNm VARCHAR(15), " & _ "CustomerLimit DOUBLE, CHECK (CustomerLimit <= " & _ "(SELECT SUM (CreditLimit) FROM CreditLimit)));" 'Dokonaj wprowadzenia conn.Execute "INSERT INTO Customers_Con (CLstNm, CFrstNm, CustomerLimit)" & _ "VALUES ('Collins', 'Kevin', 100);" 'Przejdzie do tej linii, gdy limit kredytu złamie regułę conn.Execute "INSERT INTO Customers_Con (CLstNm, CFrstNm, CustomerLimit)" & _ "VALUES ('Forte', 'Stephen', 101);" Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description, vbCritical Resume Proc_Exit End Sub Gdy nakładasz ograniczenie na pole, Jet uniemożliwi Ci wprowadzenie w tym polu wartości niezgodnej z tą zasadą. Rysunek 5.2 przedstawia komunikat o błędzie wywołany przez ostatni wiersz kodu na wydruku 5.6. Rysunek 5.2. Komunikat o błędzie wyświetlany w momencie naruszenia ograniczenia Część II Dostęp do danych Rozdział 6. Wprowadzenie do obiektów danych ActiveX W tym rozdziale: ? Historia dostępu do danych. ? Universal Data Access. ? Obiekty ActiveX Data (ADO). ? Model obiektowy ActiveX Data. ? Obiekty ADO: Recordset. ? Obiekty ADO: Error. ? Przejście z obiektów DAO do ADO. ? Porównanie modelu obiektowego ADO i DAO. Wraz z wypuszczeniem na rynek pakietu Office 2000 do rąk użytkowników trafiły też obiekty ActiveX Data. Zastąpiły one obiekty DAO oraz standard ODBCDirect i stały się jedyną metodą dostępu do danych zarówno dla Jet, jak i dla architektury klient-serwer. Od tego momentu wystarczy nauczyć się jednej metody oraz jednego modelu obiektu. Historia dostępu do danych Teraz pokażemy, jak wyglądała droga do obiektów ADO. Spoglądając na nią, będziesz mógł docenić korzyści płynące z ich używania. Firmowe interfejsy API Zanim Microsoft wprowadził na rynek swoje pierwsze produkty, jedyna droga na uzyskanie programowego dostępu do danych prowadziła przez interfejsy API poszczególnych firm. Zmuszało to programistów do poznawania różnych API dla każdego z systemów baz danych, dla których tworzyli aplikacje. Nie trzeba chyba dodawać, że rozwiązanie to było bardzo niewygodne. Open Database Connectivity (ODBC) Kilka lat temu Microsoft wprowadził na rynek specyfikację Open Database Connectivity (ODBC). Był to ogólny, programowy interfejs API, umożliwiający programistom tworzenie aplikacji dla każdej bazy danych, posiadającej sterownik ODBC. Wymagało to wprawdzie znajomości API ODBC, ale nie trzeba już było poznawać interfejsu każdej bazy, dla której tworzono aplikacje. API ODBC nie był łatwy w użyciu, jednakże był pierwszym krokiem na drodze do rozwiązania problemu istnienia tak wielu API. Jak wiecie, ODBC szybko stał się standardową metodą dostępu do danych. Microsoft Jet/Obiekty Data Access (DAO) Gdy wraz z Accessem 1.0 do rąk użytkowników trafił Microsoft Jet i obiekty Data Access (DAO), dostęp do danych został znacznie ułatwiony. Obiekty DAO dostarczały standardowego sposobu dostępu do danych dla Jet. Dodatkowo Jet mógł poprzez ODBC komunikować się z wieloma źródłami danych zgodnymi z ODBC, oraz z innymi bazami danych. Z silnika Microsoft Jet korzystały miliony użytkowników, aby dzięki jednemu modelowi obiektu dostępu danych uzyskać dostęp do różnych baz. Zdalne obiekty danych (RDO) i ODBCDirect Wydając Visual Basic 4.0 Enterprise Edition, Microsoft wprowadził nowy model obiektowy dla źródeł ODBC, zdalne obiekty danych (RDO – ang. Remote Database Objects). Obiekty RDO umożliwiały dostęp do danych ODBC z pominięciem Jet. Uzyskano dzięki temu wzrost szybkości działania aplikacji. Mimo iż obiekty RDO były krokiem naprzód, programiści (w tym również autorzy tej książki) nie byli zadowoleni z konieczności uczenia się dwóch modeli obiektowych dostępu do danych. Większość z nich pracowała już z obiektami DAO i nigdy nie nauczyła się obsługiwać RDO. Odpowiedzią Microsoftu było ODBCDirect, rozszerzenie modelu obiektowego DAO, które wykorzystywało obiekty RDO jako metody dostępu do zewnętrznych danych bez użycia Jet. Istniały już wówczas cztery metody dostępu do danych: API ODBC, DAO, RDO oraz ODBCDirect. Pomnażanie modeli obiektu osiągnęło punkt krytyczny i jasnym było, że coś należy z tym zrobić. Stąd inicjatywa Microsoftu o nazwie Universal Data Access. Universal Data Access Gdy istniało tak wiele metod dostępu do danych, Microsoft postanowił, poprzez inicjatywę Universal Data Access, stworzyć nowy standard. Pierwszym etapem jej wprowadzania były bazy danych OLE – otwarta specyfikacja zaprojektowana jako kontynuacja sukcesu ODBC. Bazy danych OLE to otwarty standard, umożliwiający dostęp do każdego rodzaju danych. ODBC stworzono jako metodę dostępu do danych w bazach relacyjnych, podczas gdy bazy danych OLE zaprojektowano z myślą zarówno o relacyjnych jak i nierelacyjnych źródłach danych (skrzynki pocztowe, tekstowe i graficzne dane w sieci WWW, usługi katalogowe oraz przechowywane na komputerach klasy mainframe dane IMS i VSAM). ODBC używa sterowników ODBC do komunikowania się ze źródłami danych, natomiast bazy danych OLE wykorzystują do tego celu dostawców danych. Bazy danych OLE umożliwiają nauczenie się tylko jednego modelu obiektowego dla wszystkich baz a nawet używanie tego modelu podczas pracy z nierelacyjnymi źródłami danych. Technologia OLE to znaczny postęp w porównaniu z ODBC, ponieważ potrafi porozumiewać się z wieloma różnymi źródłami danych. Aby zapewnić kompatybilność z poprzednimi wersjami, do baz danych OLE dołączono dostawcę dla ODBC. Dzisiaj istnieją również dostawcy dla Jet, SQL Server, Oracle, NT 5 Active Directory i wielu innych programów. Rysunek 6.1 przedstawia aktualny wygląd technologii Universal Data Access. Głównymi obiektami dostępu do danych baz OLE są obiekty ActiveX Data (ADO). Jak widzisz, zarówno bezpośrednio, jak i poprzez obiekty ADO, bazy danych OLE mogą komunikować się z innymi bazami (relacyjnymi lub nie) oraz danymi na komputerze głównym za pomocą jednego interfejsu. Rysunek 6.1 Schemat dostępu do danych – stan na dzień dzisiejszy Obiekty ActiveX Data (ADO) Obiekty ActiveX Data (ADO) to model obiektowy, którego możesz używać w celu pobierania danych z baz OLE. Technologia ta istniała już od pewnego czasu, a od wersji 2.0 stała się preferowaną przez Microsoft metodą dostępu do danych. Przyjrzyjmy się historii obiektów ADO. ADO 1.0 Po wprowadzeniu na rynek w końcu roku 1996 obiekty ADO używane były głównie jako metoda dostępu do danych poprzez skrypt w opartych na Active Server Pages aplikacjach internetowych. Posiadały one jedynie podstawowy zestaw funkcji służący jako dostęp do danych w architekturze typu klient-serwer. W tym czasie obiekty ADO służyły jako podzestaw dla popularnych modeli obiektów DAO i RDO. Programiści używali jedynego dostępnego dostawcy OLEDB – ogólnego dostawcy dla wszystkich źródeł danych ODBC. ADO 1.5 Jesienią 1997 roku Microsoft wprowadził na rynek ADO 1.5 oraz Microsoft Data Access Components 1.0 (MDAC) i IIS 4.0. Obiekty ADO w wersji 1.5 zawierały między innymi: Remote Data Services (RDS) i obsługę zestawów rekordów odłączonych od bazy. Pierwszym dostawcą baz danych OLE, który ujrzał światło dzienne, był dostawca dla aparatu Jet o nazwie JOLT. ADO 2.0 Latem 1998 roku, wraz z wypuszczeniem wersji 2.0 MDAC, powstała trzecia wersja obiektów ADO – ADO 2.0. Był to prawie nadzestaw RDO 2.0 i DAO 3.5, zawierający dodatkowo kilka interesujących opcji. Do ADO 2.0 dołączono również dostawców baz danych OLE dla Jet, SQL Server i Oracle. Wiele z nowych opcji było już wcześniej wykorzystanych w obiektach RDO i DAO, włączając w to operacje asynchroniczne i powtórną synchronizację poprzez kursory klienta. Obiekty ADO zawierały też zupełnie nowe technologie, jak: ? Microsoft Data Links. ? Stałe zestawy rekordów. ? Zestawy rekordów tworzone przez użytkownika. ? Zestawy rekordów OLAP. Wszystkie te technologie opisane są w rozdziale 7., „Zaawansowane ADO”. ADO 2.1 Wydane wraz z SQL Serverem 7.0, pakietem Office 2000 i Internet Explorerem 5.0 obiekty ADO w wersji 2.1 zawierają wszystkie opcje umieszczone w wersji 2.0 oraz dwa nowe modele obiektu: ? ADO – dla operacji DDL i zabezpieczeń (ADOX); ? JRO (Jet Replication Objects) – dla opcji replikacji oraz funkcji zmniejszania i naprawiania baz danych w silniku Jet. Do operacji związanych z Accessem i silnikiem Jet nie należy używać wersji ADO dostarczanej wraz z SQL Serverem 7.0. Zawiera ona błędy i nie wszystkie opcje opisane w tym i pozostałych rozdziałach będą w niej funkcjonować. Upewnij się, że używasz wersji ADO dostarczanej wraz z pakietem Office 2000 lub systemem NT 2000. ADOX najlepiej współpracuje z JOLT, jednakże działa również z SQL Server i innymi dostawcami. JRO jest rozszerzeniem przeznaczonym dla Jet, używanym głównie podczas replikacji. Model ADOX omówiony zostanie w następnym rozdziale, a JRO w rozdziale 22., „Replikacja i JRO”. Jak wszystko w tej branży obiekty ADO i bazy danych OLE są przez cały czas udoskonalane. Trudno jest czasami nadążyć za zmianami. Jako że Microsoft wydaje nowe wersje obiektów ADO niezależnie od pakietu Office i naszej książki, więcej informacji i najnowsze szczegóły znajdziesz na stronie WWW poświęconej tym zagadnieniom. Umieszczono na niej mnóstwo próbek kodu i dokumentacji technicznej. Strona ta przedstawiona jest na rysunku 6.2 i znajduje się pod adresem http:// www.microsoft.com/data. Rysunek 6.2. Strona WWW dotycząca obiektów ADO i baz OLE Model obiektowy ADO Model obiektu ADO jest bardzo prosty i płaski. W przeciwieństwie do modeli DAO i RDO model ADO nie jest hierarchiczny. Znajduje się on na rysunku 6.3. Rysunek 6.3. Model obiektowy ADO Model obiektowy ADO składa się z siedmiu obiektów: ? Connection. ? Recordset. ? Command. ? Parameter. ? Field. ? Property. ? Error. Ponieważ obiekty ADO oparte są na wspólnym modelu obiektowym (COM), tworzenie ich powinno być Ci już znane. Przykładowo, możesz utworzyć obiekt połączenia ADO w taki sposób: Dim conn As ADODB.Connection Set conn= New ADODB.Connection Po utworzeniu obiektu możesz ustawić jego właściwości lub uruchomić go, na czym skupimy się w pozostałej części tego rozdziału. Obiekt Connection Obiekt Connection przedstawia fizyczne połączenie do bazy lub dostawcy danych. Możesz otworzyć połączenie, wskazując obiektowi Connection, którego dostawcy ma użyć, oraz określając ciąg połączeniowy. Kod ten przedstawiony jest na wydruku 6.1 i znajdziesz go w pliku Rozdz06.mdb na dołączonej do książki płycie CD-ROM. Wydruk 6.1. Łączenie z bazą danych Accessa poprzez ADO i obiekt Connection Sub ConnectToDatabase() 'Procedura ta spowoduje utworzenie połączenia z bazą 'danych Accessa przy użyciu dostawcy OLE DB dla Jeta 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection On Error GoTo Proc_Err 'Utwórz obiekt połączenia Set conn = New ADODB.Connection With conn 'Ustaw właściwość dostarczyciela 'W ten sposób nakazujemy Ado użycie JOLT .Provider = "Microsoft.Jet.OLEDB.4.0" 'W ciągu połączenia określ ścieżkę 'W tym miejscu możesz określić informacje 'dotyczące zabezpieczeń (co opisaliśmy w kolejnych rozdziałach) .ConnectionString = "data source=C:\northwind.mdb" 'W ten sposób określamy tryb otwarcia bazy 'Możesz teraz dokonać wyboru między trybem "z wyłącznością" 'a "tylko do odczytu" .Mode = adModeReadWrite 'Use the open method .Open End With MsgBox "Połączony poprzez " & conn.Provider & _ " dostawcę OLE DB!", vbInformation Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description, vbCritical Resume Proc_Exit End Sub Na wydruku tym wykorzystaliśmy następujące właściwości obiektu Connection: ? Provider. ? ConnectionString. ? Mode. Provider jest ciągiem przedstawiającym unikatowy ProgID wybranego dostawcy OLEDB. My wybraliśmy „Microsoft.Jet.4.0”, który jest dostawcą OLEDB dla Jet 4.0. Ciąg połączeniowy (ConnectionString) to określenie ścieżki dostępu do bazy oraz innych informacji dotyczących połączenia, jak na przykład lokalizacja pliku grupy roboczej, czy zabezpieczenia (więcej informacji o zabezpieczeniach w rozdziale 23.). Później ustawiliśmy właściwość Mode na stałą ADO adModeReadWrite. Umożliwia nam to uruchomienie bazy danych w trybie Odczyt/Zapis. W tym miejscu możesz również nakazać otwieranie bazy danych jedynie w trybie tylko do odczytu. Otwarcie połączenia w Accessie 2000 Gdy używasz ADO w aplikacji działającej w Accessie 2000, określenie ciągu połączeniowego do tej samej bazy jest krótsze. Ponieważ Access sam korzysta z globalnego obiektu Connection (jak CurrentDB w starszych wersjach DAO), możesz określić właściwość Connection, używając obiektu CurrentProject.Connection: Dim conn As ADODB.Connection Set conn = CurrentProject.Connection Wykonywanie wyrażeń SQL w obiekcie Connection W aktualnym obiekcie Connection możesz wykonywać instrukcje SQL. Przypomina to wykonywanie metod z obiektu bazy danych w DAO. Wydruk 6.2 przedstawia, jak wykonywać wyrażenie SQL w obiekcie Connection. Wydruk 6.2. Wykonywanie wyrażenia SQL w obiekcie Connection Sub ConnExecute() 'Procedura ta spowoduje utworzenie połączenia z bazą 'danych Accessa przy użyciu dostawcy OLE DB dla Jeta, 'a następnie wykona polecenie 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection Dim strSQL As String Dim lngRecordsAffected As Long On Error GoTo Proc_Err 'Utwórz obiekt połączenia Set conn = New ADODB.Connection With conn 'Ustaw właściwość dostarczyciela 'W ten sposób nakazujemy Ado użycie JOLT'a .Provider = "Microsoft.Jet.OLEDB.4.0" 'W ciągu połączenia określ ścieżkę .ConnectionString = "data source=C:\northwind.mdb" .Mode = adModeReadWrite .Open End With 'SQL Statement strSQL = "UPDATE Customers SET Customers.Region = " & _ Chr(39) & "YK" & Chr(39) & vbNewLine & _ "WHERE (((Customers.Region)=" & _ Chr(39) & "BC" & Chr(39) & "));" conn.Execute strSQL, lngRecordsAffected MsgBox lngRecordsAffected & " rekordy zaktualizowane!", vbInformation Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description, vbCritical Resume Proc_Exit End Sub Nasze wyrażenie zmieni wszystkie wiersze tabeli Customers, w których wartość pola Region="BC", w taki sposób, by wartość tego pola była równa "YK". Zauważ, że możesz dowiedzieć się, ile rekordów zostało zmienionych, dodając zmienną do metody Execute, a następnie sprawdzając wartość tej zmiennej. Obiekty ADO: Recordset Obiekt Recordset jest programowym zbiorem danych pochodzących z tabeli, kwerendy lub procedury SQL. Posiada on pola, w których znajdują się dane z wierszy tabeli lub kwerendy, na której jest oparty. Aby otworzyć ten obiekt, musisz użyć następującej składni: Recordsetobject.Open "Statement", _ ActiveConnection, CursorType, LockType, Options W tabeli 6.1 znajdują się opisy każdego z parametrów. Wydruk 6.3 przedstawia, jak otworzyć zestaw rekordów oparty na tabeli Customers. Utworzyliśmy połączenie oparte na aktualnej bazie danych, a następnie otwarliśmy zestaw rekordów z kursorem tylko do przekazania, tylko do odczytu. Użyliśmy także parametru adCmdTableDirect, który „każe” Accessowi otworzyć tabelę bezpośrednio. Wydruk 6.3. Otwarcie obiektu Recordset Sub OpenRecordset() 'Procedura ta spowoduje otwarcie w aktualnej bazie 'zestawu rekordów opartego na tabeli Customers, 'a następnie wydrukuje te rekordy 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection Dim rst As ADODB.Recordset On Error GoTo Proc_Err 'Utwórz połączenie Set conn = CurrentProject.Connection 'Utwórz nowy zestaw rekordów Set rst = New ADODB.Recordset 'Otwórz zestaw rekordów rst.Open "Customers", _ conn, adOpenForwardOnly, adLockReadOnly, adCmdTableDirect 'Utwórz pętlę w zestawie rekordów Do Until rst.EOF Debug.Print rst!CompanyName rst.MoveNext Loop 'Zamknij i usuń zestaw rekordów rst.Close Set rst = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description, vbCritical Resume Proc_Exit End Sub Tabela 6.1. Parametry otwarcia obiektu Recordset Argument Wymagany Uwagi Domyślnie Statement Tak Nazwa tabeli, kwerendy bądź prawidłowe wyrażenie SQL – ActiveConnection Tak Prawidłowy obiekt Connection bądź prawidłowy ciąg połączenia – Cursor Type Nie adOpenDynamic – Możliwość przeglądania zmian w zestawie rekordów, nawet tych dokonanych przez innych użytkowników adOpenForwardOnly – Przekazywanie dalej jedynie nieprzewijalnych zestawów rekordów adOpenKeyset – Brak możliwości przeglądania zmian dokonanych przez innych użytkowników; możliwość przeglądania zmian dokonanych przez aktualnego użytkownika adOpenStatic – Brak możliwości przeglądania zmian w zestawie rekordów adOpenForwardOnly Lock Type Nie adLockBatchOptimistic – Blokuje rekordy w programie wsadowym adLockOptimistic – Blokowanie optymistyczne adLockPessimistic – Blokowanie pesymistyczne adLockReadOnly – Tylko do odczytu adLockReadOnly Options Nie adCmdFile – otwarcie przechowywanego na dysku zestawu rekordów adCmdStoredProc – Przechowywana procedura SQL Server lub kwerenda Accessa adCmdTable – wykonanie na tabeli polecenia Select * From adCmdTableDirect – Bezpośrednie otwarcie tabeli (jak db OpenTable w DAO) adCmdText – Procedura SQL adCmdUnknown – Wartość nieznana, Access określi ją za ciebie adCmdUnknown Na wydruku 6.3 użyliśmy obiektu Connection, bazującego na aktualnym połączeniu: 'Otwórz zestaw rekordów rst.Open "Customers", _ conn, adOpenForwardOnly, adLockReadOnly, adCmdTableDirect W Accessie 2000 możesz użyć wyrażenia CurrentProject.Connection: 'Otwórz zestaw rekordów rst.Open "Customers", _ CurrentProject.Connection, _ adOpenForwardOnly, adLockReadOnly, adCmdTableDirect Możesz także dodać informacje o połączeniu – ciąg oraz polecenie dynamicznego otwarcia połączenia bez obiektu Connection: 'Otwórz zestaw rekordów rst.Open "Customers", "provider=Microsoft.Jet.OLEDB.4.0; " & _ "data source c:\northwind.mdb", _ adOpenForwardOnly, adLockReadOnly, adCmdTableDirect Dodatkowo, oprócz otwarcia tabeli, możesz również otworzyć zestaw rekordów oparty na wyrażeniu SQL: Rst.Open "Select * From Customers Where CustomerID= ALFKI", _ CurrentProject.Connection, _ adOpenForwardOnly, adLockReadOnly, adCmdTableDirect Jak wiadomo, jedną z najważniejszych opcji silnika Jet jest wydajna praca z zewnętrznymi danymi. Aby otworzyć zewnętrzne źródło danych, będziesz musiał zmodyfikować ciąg połączenia. Źródło danych musi wskazywać na zewnętrzny plik, do którego chcesz uzyskać dostęp (tekstowy, DBF, Excela lub inny), a także musi być ustawiona właściwość „Zaawansowane właściwości” indeksowego dostępu sekwencyjnego do plików. Kolejny przykład fragmentu kodu przedstawia, w jaki sposób Jet może poprzez ADO uzyskać dostęp do arkusza kalkulacyjnego Excel 8.0. W poniższym przykładzie otworzymy zestaw rekordów oparty na danych w arkuszu „Sheet1” pliku Customers.xls: Dim conn As ADODB.Connection Dim rst As ADODB.Recordset With conn .Provider = "Provider=Microsoft.Jet.OLEDB.4.0." .ConnectionString = "Data Source=C:\excel\Customers.xls;" &_ "Extended Properties=Excel 8.0;" .Open End With Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "Sheet1$", conn, _ adOpenDynamic, adLockOptimistic, adCmdTableDirect Użycie Recordset z obiektami Command i Parameter Obiekt Command przedstawia dość specyficzne polecenie, które będziesz wykonywał na źródle danych poprzez jego dostawcę. Przykładem polecenia jest kwerenda funkcjonalna. Możesz również użyć Command w połączeniu z obiektem Parameter, w celu wykona- nia kwerend parametrycznych w Accessie lub procedur przechowywanych serwera SQL. Obiekt Parameter odnosi się do parametru lub argumentu związanego z obiektem Command. Przyjrzyjmy się teraz, w jaki sposób wykonać zapisaną kwerendę parametryczną Accessa. Kwerenda ta znajduje się na płycie CD-ROM, w pliku Rozdz06.mdb, pod nazwą qryCustOrders_Prm. Oto jej treść w SQL: PARAMETERS OrderID Long; SELECT Orders.* FROM Orders AS Orders WHERE (((Orders.OrderID)=[OrderID])); W siatce QBE Accessa zdefiniowaliśmy naszą kwerendę i utworzyliśmy dla niej parametr, korzystając ze znajdującej się w menu Kwerenda opcji Parametry. Parametry zdefiniowaliśmy w sposób przedstawiony na rysunku 6.4. Rysunek 6.4. Okno dialogowe Parametry kwerendy Teraz tworzymy obiekt Command i określamy, którego obiektu Connection będziemy używać i jaki to typ polecenia. Każemy mu użyć utworzonego przed chwilą obiektu Connection, a następnie wskazujemy na znajdującą się w bazie kwerendę qryCustOrders_Prm. Możesz użyć tych samych opcji dla zestawu rekordów w przypadku obiektu Command. Dim cmd as ADODB.Command Set cmd = New ADODB.Command With cmd .ActiveConnection = conn .CommandText = “qryCustOrders_Prm" .CommandType = adCmdStoredProc End With Ustawiliśmy właściwość CommandType na adCmdStoredProc, ponieważ ADO/Jolt traktuje zapisane kwerendy jak procedury. Następnym rodzajem CommandType jest adCmdTable, używane w starszych wersjach Jet. Gdy konwertujesz aplikacje z Jet 3.51 do 4.0 w Accessie 2000 lub VB6, pamiętaj o różnicy w działaniu tych dwóch metod. W przypadku Jet 3.51 musisz określić CommandType jako adCmdTable, natomiast w aparacie Jet 4.0 powinieneś użyć adCmdStoredProc. Aby ustawić informacje o parametrze, wystarczy określić cztery właściwości: Name, Type, Value i Direction. Nazwę (Name) i typ danych (Type) wpisz takie same jak w zapisanej kwerendzie Jet. Będziesz musiał również określić właściwość Direction, która informuje ADO, czy parametr jest wartością wejściową, wyjściową czy zwracaną. Teraz ustaw wartość parametru, opierając się na tym, co użytkownik określił w aplikacji, a następnie dodaj parametr do zbioru parametrów obiektu Command. Gdy używasz obiektów Command, Jet obsługuje jedynie parametry wejściowe. SQL Server oraz inne serwery baz danych potrafią obsługiwać parametry wyjściowe w zapisanych procedurach, tak więc nie próbuj wprowadzać parametrów wyjściowych. With prm .Name = "OrderID" .Value = 10248 .Type = adInteger .Direction = adParamInput End With cmd.Parameters.Append prm Teraz korzystamy z metody Execute obiektu Command, aby utworzyć obiekt Recordset. Możesz użyć danych z zestawu rekordów, aby wypełnić pola tekstowe w formularzu VB lub wykonać obliczenia. Aby otrzymać dane z wykonanego polecenia, musisz ustawić Recordset na wykonane polecenie w następujący sposób: Set rst = cmd.Execute Wydruk 6.4 łączy te wszystkie przykłady i otwiera zestaw rekordów oparty na wykonanym poleceniu. Wydruk 6.4. Wykonywanie polecenia Sub OpenRecordsetviaCommand() 'Procedura ta spowoduje otwarcie w aktualnej bazie 'zestawu rekordów opartego na obiekcie Command, 'Obiekt ten będzie odwoływał się do znajdującej się w bazie 'kwerendy qryCustOrders_Prm 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection Dim rst As ADODB.Recordset Dim cmd As ADODB.Command Dim prm As ADODB.Parameter On Error GoTo Proc_Err 'Utwórz połączenie Set conn = CurrentProject.Connection Set cmd = New ADODB.Command With cmd .ActiveConnection = conn .CommandText = "qryCustOrders_Prm" .CommandType = adCmdTable End With Set prm = New ADODB.Parameter With prm .Name = "OrderID" .Value = 10248 .Type = adInteger .Direction = adParamInput End With cmd.Parameters.Append prm Set rst = cmd.Execute 'Utwórz pętlę w zestawie rekordów Do Until rst.EOF Debug.Print rst!OrderDate rst.MoveNext Loop 'Zamknij i usuń zestaw rekordów rst.Close Set rst = Nothing Set cmd = Nothing Set prm = Nothing Set conn = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description, vbCritical Resume Proc_Exit End Sub Wykonywanie kwerendy funkcjonalnej poprzez obiekt Command Możesz wykonywać zapisane kwerendy funkcjonalne Accessa poprzez obiekt Command. W pliku Rozdz06.mdb znajduje się kwerenda qryUpdateTitle, aktualizująca stanowisko każdego z pracowników w tabeli Customers, od Account Manager do Account Executive. Oto ta kwerenda w języku SQL: UPDATE Customers SET Customers.ContactTitle = "Account Executive" WHERE (((Customers.ContactTitle)="Account Manager")); Aby uruchomić tę kwerendę programowo poprzez ADO, musisz utworzyć obiekt Command, skojarzyć go z obiektem Connection i wykonać. Wydruk 6.5 przedstawia, jak tę czynność wykonać. Wydruk 6.5. Wykonywanie kwerendy funkcjonalnej Accessa poprzez ADO Sub ActionQueryCmd() 'Procedura ta spowoduje uruchomienie kwerendy funkcjonalnej 'poprzez obiekt Command, a następnie wydrukuje właściwości 'zestawu rekordów 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim cmd As ADODB.Command Dim lngRecordsAffected As Long On Error GoTo Proc_Err Set cmd = New ADODB.Command Dim rst As ADODB.Recordset With cmd 'Połącz z aktualną bazą danych .ActiveConnection = CurrentProject.Connection 'Nazwa kwerendy w Accessie .CommandText = "qryUpdateTitle" 'Ustaw tę własciwość jako adCmdStoredProc, Jet zaklasyfikuje 'Zapisane Kwerendy jako procedury dla obiektu Command .CommandType = adCmdStoredProc 'Uruchom kwerendę .Execute, lngRecordsAffected End With MsgBox lngRecordsAffected & " rekordy zaktualizowane!", _ vbInformation Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Obiekty Field i Property Obiekty Field i Property świetnie nadają się do odnajdywania informacji o tabeli lub zestawie rekordów. Obiekt Field przedstawia każdą kolumnę pól w zestawie rekordów. Obiekt Property przedstawia każdą właściwość, niezależnie od tego, jakiego obiektu dotyczy kwerenda. Możesz przechodzić przez każde pole w zestawie rekordów lub właściwość zmiennej obiektu poprzez składnię For...Each – patrz wydruk 6.6. Wydruk 6.6. Wykorzystanie obiektów Field i Property poprzez ADO Sub FieldandProperty() 'Procedura ta spowoduje wydrukowanie wszystkich pól 'zestawu rekordów wraz z ich wartościami oraz właściwości 'zestawu rekordów 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim rst As ADODB.Recordset Dim fld As ADODB.Field Dim prp As ADODB.Property On Error GoTo Proc_Err Set rst = New ADODB.Recordset 'Otwórz zestaw rekordów oparty na tabeli klienci rst.Open "Customers", CurrentProject.Connection 'Wydrukuj nazwę i wartość każdego pola Debug.Print "Table Fields:" For Each fld In rst.Fields Debug.Print fld.Name & ": " & fld.Value Next fld 'Wydrukuj właściwości tabeli Debug.Print Debug.Print "Table Properites:" For Each prp In rst.Properties Debug.Print prp.Name Next prp rst.Close Set rst = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Obiekty ADO: Error Podczas pisania kodu zdarza się popełnić błąd lub umożliwić dokonywanie zmian poza kontrolą użytkownika (jak na przykład umożliwić administratorowi sieci LAN przeniesienie bazy danych bez poinformowania Cię o tym). Obiekt Connection posiada zbiór obiektów Error, które przedstawiają każdy z występujących błędów. Obiekt Error posiada kilka istotnych właściwości. Umieściliśmy je w tabeli 6.2. Tabela 6.2. Główne właściwości obiektu Error Właściwość Komentarz Description Opis błędu Number Numer błędu ADO Native Error Numer błędu dostawcy SQL State Kod błędu charakterystyczny dla dostawcy. W silniku Jet oznacza on dawny numer błędu DAO Source Źródło błędu. W naszym przypadku będzie to Jet Ponieważ dowolny błąd w kodzie może powodować wiele błędów ADO, możesz przeglądać zbiór błędów obiektu Connection, a następnie sprawdzać poszczególne właściwości. Jeśli użyłeś w aplikacji kodu opartego na dawnej numeracji błędów DAO, aby uzyskać kompatybilność wstecz będziesz zmuszony użyć właściwości SQLState. Dzięki niej uzyskasz dawny kod błędu DAO. Możesz przeglądać zbiór błędów, korzystając z obiektu Error (wydruk 6.7). Wynik działania programu z wydruku 6.7 znajduje się na rysunku 6.5. Wydruk 6.7. Użycie obiektu Error Sub ConnErrHandle() 'Procedura ta wymusi powstanie błędu, a następnie 'użyje obiektu Error w celu uzyskania informacji o tym błędzie 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection Dim rst As ADODB.Recordset On Error GoTo Proc_Err Set conn = CurrentProject.Connection Set rst = New ADODB.Recordset Rysunek 6.5. Komunikat o błędzie wykorzystujący obiekt Error 'Wymuś błąd rst.Open "badTable", conn Proc_Exit: Exit Sub Proc_Err: Dim adoErr As ADODB.Error 'Przejdź przez każdy z błędów 'w zbiorze błędów połączenia For Each adoErr In conn.Errors 'Dla każdego z błędów wyświetl komunikat MsgBox "Błąd ADO: " & adoErr.Description & _ vbNewLine & "Błąd wewnętrzny: " & _ adoErr.NativeError & _ vbNewLine & "Procedura SQL: " & _ adoErr.SQLState & _ vbNewLine & "Źródło: " & _ adoErr.Source, vbCritical, _ "Kod błędu: " & adoErr.Number Next adoErr Resume Proc_Exit End Sub Przejście z obiektów DAO do ADO Wstęp do obiektów ADO wykazał, że istnieje wiele podobieństw między nimi a obiektami DAO. Przez całą tę książkę będziemy pokazywać, w jaki sposób możesz korzystać z obiektów ADO, porównując je do DAO. Ta część stanowi wstęp do procesu konwersji oraz porównanie tych dwóch modeli obiektu. Konwersja z poprzednich wersji Accessa Podczas przeprowadzania konwersji z poprzedniej wersji bazy danych Accessa do Accessa 2000 powinieneś wziąć pod uwagę, że ADO jest nową, domyślną metodą dostępu do danych. Może to powodować zamieszanie podczas tworzenia obiektu o tej samej nazwie w ADO jak i w DAO (na przykład „recordset”). Jeśli w Accessie użyjesz następującego kodu: Dim db As Database Dim rst as Recordset Access 2000 przyjmie, że zmienna rst będzie rekordem ADO, a nie DAO, ponieważ ADO domyślnie znajduje się wyżej w odwołaniach VBA. Przed dokonaniem konwersji baz danych z Accessa 97, 95 lub innych powinieneś przed nazwami obiektów DAO umieścić przedrostek DAO. Powyższy kod powinien wyglądać następująco: Dim db As DAO.Database Dim rst as DAO.Recordset Pozwoli to wyeliminować możliwość pomyłki w zmiennych obiektu DAO podczas konwersji. Czy warto przejść na obiekty ADO? W wypadku tworzenia nowej aplikacji w Accessie 2000 odpowiedź jest jedna: używać ADO. Lecz co w sytuacji, gdy konwertujemy do Accessa 2000 już istniejąca aplikację? Wówczas przejście na obiekty ADO również powinno być brane pod uwagę. Z pewnością zechcesz przejść na obiekty ADO jak najszybciej, by móc korzystać z opcji niedostępnych w DAO. Poza tym, Microsoft zapowiedział odejście od technologii DAO, więc w kolejnych wersjach Accessa obiekty DAO nie będą bezpośrednio obsługiwane. Ponieważ przyszłość należy do technologii ADO, powinieneś poważnie rozważyć jej wprowadzenie. Czy masz na to czas? Pieniądze? Elementami, które powinieneś brać w tych rozważaniach pod uwagę, powinny być poziom Twoich umiejętności oraz wysokość budżetu. Książka ta oraz znajdująca się na stronie WWW Microsoftu dokumentacja dotycząca obiektów ADO (http://www.microsoft.com.data) powinny przygotować Cię do nauki obsługiwania tej technologii. W następnej części znajduje się opis przygotowania typowego planu konwersji. Poznanie technologii ADO i proces konwersji kodu aplikacji z DAO do ADO powinny być częścią budżetu przeznaczonego na konwersję. Proces konwersji do Accessa 2000 wymaga więcej czasu niż typowa konwersja. Postępując według poniższych wskazówek, będziesz mógł zaoszczędzić dużo czasu, pieniędzy i wysiłku. Schemat konwersji W tej części pokażemy, jak powinieneś podejść do procesu konwersji aplikacji z DAO do ADO. Pamiętaj, zawsze sporządzaj kopie zapasowe swojej pracy! 5. Uruchom Accessa 97. Jeśli aplikacja jest w starszej wersji niż Access 97, najpierw musisz ją skonwertować do Accessa 97. 6. Przeanalizuj koszty. Dokonaj analizy bazy danych, aby określić, jak wiele procedur używa DAO. Następnie sporządź w Excelu listę wszystkich procedur i oceń, ile czasu zajmie konwersja każdej z nich. 7. Ze strony WWW Microsoftu pobierz i zainstaluj ADO 2.1. 8. Rozpocznij konwersję od procedur, które nie komunikują się z innymi. Gdy skończysz konwersję jednej procedury, dwukrotnie ją przetestuj. Dopiero wtedy przejdź do kolejnej. W zależności od wielkości bazy danych, operacja ta może trwać dni lub nawet tygodnie. 9. Nie usuwaj starych procedur. Zmieniaj ich nazwy na NazwaProcedury_DAO, dodając na końcu _DAO, aby móc szybko zmienić nazwę procedury ADO (używającej końcówki _ADO) i podmienić procedurę DAO podczas testowania. 10. Po skonwertowaniu kodu w osobnych procedurach zacznij oględziny kodu tych większych i bardziej złożonych. Nie trać czasu na poprawianie innych rzeczy w tych procedurach. Na dokonanie poprawek przyjdzie czas później. Zmień tylko kod DAO. Użyj tej samej metodologii testowania, co w punkcie 5. 11. Po skonwertowaniu całego kodu przetestuj jednocześnie obie wersje aplikacji. Później przekaż nową aplikację do testów innemu programiście. 12. Utwórz metody, które umożliwią użytkownikom łatwe wycofywanie dokonanych zmian. Dzięki temu, jeśli aplikacja powoduje błędy w danych, użytkownicy będą mogli powrócić do poprzedniego stanu. 13. Oddaj do rąk użytkowników wersję beta, by mogli przetestować ją w codziennym użyciu. Do testowania wersji ADO wybierz kilku wiarygodnych użytkowników. Nie usuwaj poprzedniej, działającej wersji DAO. Utwórz skrót do niej, na wypadek wystąpienia błędów zakłócających pracę użytkowników. 14. Gdy jesteś już pewien, że użytkownicy w wystarczający sposób przetestowali aplikację, przeprowadź konwersję do Accessa 2000 i powtórz kroki 7–9. Upewnij się, że użytkownicy faktycznie testują aplikację! Aby sprawdzić, czy użytkownicy faktycznie testują aplikację w wystarczający sposób, możesz dołączyć do niej technikę, której używamy my. Nie chcemy być obarczani odpowiedzialnością za błędy, które użytkownik mógł znaleźć podczas testowania, więc w wersjach beta umieszczamy bardzo szczegółowe oprogramowanie monitorujące. Podczas uruchamiania każdej procedury, nawet tak prostej jak przycisk Zamknij, zapisujemy w bazie wszelkie informacje. Dzięki temu wiemy, jak często dany użytkownik uruchamiał określoną procedurę, a nawet jak często tworzył dany raport. Później analizujemy te dane i w zależności od wyników tej analizy prosimy użytkowników o przetestowanie określonych części aplikacji. Procedura ta daje nam pewność, że użytkownicy przetestowali wszystkie elementy, zanim przekształcimy wersję beta w wersję końcową. Kiedy nie dokonywać konwersji? Niewielkie projekty, z małym budżetem, nie powinny być konwertowane do technologii ADO. Jak widzisz, procedura testowania składa się z wielu etapów. Jeśli użytkownicy nie są w stanie pokryć kosztów testowania, zaniechaj konwersji. Technologia DAO działa zadowalająco w Accessie 2000. Co więcej, w DAO 3.6 poprawiono kilka błędów, tak więc kod napisany w tej technologii powinien bez żadnych modyfikacji działać lepiej w Accessie 2000 niż 97. W trakcie czytania tej książki natrafisz na operacje, które DAO wykonuje lepiej niż ADO (niektóre operacje dotyczące DDL oraz zabezpieczeń). Jeśli aplikacja w znacznej części opiera się na tych technikach, lepiej będzie jej nie konwertować lub zdecydować się na połączenie obu technologii. Porównanie modelu obiektowego ADO i DAO DAO posiada olbrzymi model obiektowy, składający się z ponad 50 elementów. Model obiektowy w technologii ADO jest dużo mniejszy i zawiera ich jedynie 7. Gdzie podziała się reszta? W tej części zobaczysz, jak wygląda porównanie dostępu do danych w obu tych technologiach. Temat ten został omówiony w rozdziałach 22. „Replikacja i JRO” i 7. „Zaawansowane ADO”. W tabeli 6.3 znajdziesz najbardziej powszechne obiekty związane z dostępem do danych w DAO i ich odpowiedniki w technologii ADO. Tabela 6.3. Porównanie obiektów DAO i ADO Obiekt DAO Obiekt ADO DBEngine Brak Workspace Brak Database Connection Recordset Recordset Field Field QueryDef Command Parameter Parameter Error Error Rozdział 7. Zaawansowane ADO W tym rozdziale: ? Użycie dostawcy OLE DB dla Accessa. ? Uzyskanie poprzez ADO dostępu do danych w bazach nierelacyjnych. ? Zaawansowana obróbka danych przy użyciu ADO. ? Definiowanie danych przy użyciu ADOX. Teraz, kiedy już umiesz używać obiektów ADO i porównałeś je z DAO, przyjrzyj się tym cechom ADO, które pomogą Ci tworzyć aplikacje w Accessie 2000. Użycie dostawcy OLE DB dla Jet w Accessie 2000 Gdy używasz ADO w aplikacjach Accessa, najprawdopodobniej będziesz korzystał z dostawcy OLE DB dla Jet (użycie dostawcy OLE DB dla SQL Server jest omówione w rozdziale 15). Dostawca ten pozwala na bezpośredni dostęp do plików typu MDB. Zdolność bezpośredniej komunikacji ze źródłem danych to wielki krok naprzód dla ADO. Aby użyć dostawcy OLE DB dla Jet, musisz podać jego nazwę i pełną ścieżkę dostępu do bazy danych jako część ciągu połączeniowego. Aby zachować przejrzystość, umieszczono w ADO właściwość Provider, której odpowiednie ustawienie umożliwi użycie dostawcy dla Jet. Jego unikatowym CLASSID w ciągu połączenia jest: Microsoft.Jet.OLEDB.4.0. Poniższy przykład przedstawia, jak tworzyć połączenie do bazy Microsoft Accessa przy użyciu dostawcy OLE DB dla Jet: Dim conn As ADODB.Connection Set conn = New ADODB.Connection With conn .Provider = "Microsoft.Jet.OLE.DB.4.0" .ConnectionString = "data source= C:\databases\sample.mdb" .Open End With Jeśli zachodzi konieczność określenia innych informacji dotyczących połączenia (np. hasło bazy danych czy plik grupy roboczej), dołącz je do ciągu połączeniowego, poprzedzając średnikiem. W tabeli 7.1 znajdziesz charakterystyczne dla dostawcy właściwości połączenia, których możesz użyć w ciągu połączeniowym. Inne charakterystyczne dla dostarczyciela właściwości, które znajdują się w zbiorze właściwości połączenia, zostaną zignorowane. Tabela 7.1. Właściwości ciągów połączenia charakterystyczne dla dostawcy OLE DB dla Microsoft Jet Nazwa Opis Jet OLEDB:Registry Path Ścieżka dostępu do klucza rejestru dla Jet. Nie zawiera znacznika HKEY_LOCAL_MACHINE. Wartość ta może zostać zamieniona na drugorzędną lokalizację w celu przechowywania wartości rejestru aplikacji, które nie są współdzielone z innymi aplikacjami korzystającymi z Jet na tym komputerze. Przykładowo, ustawienie dla Accessa 2000 to: SOFTWARE\Microsoft\Office\9.0\Access\Jet\4.0\Engines Jet OLEDB:System database Lokalizacja systemowej bazy Jet, która ma być używana przez określonych użytkowników. Powoduje to unieważnienie wartości ustalonej w rejestrze lub klucza rejestru systemdb używanego wraz z Jet OLEDB:Registry Path. Właściwość ta może zawierać ścieżkę dostępu do pliku. Jet OLEDB:Database Password Hasło używane do otwarcia bazy danych. Od hasła użytkownika różni się tym, że hasło bazy danych dotyczy pliku a nie konkretnego użytkownika. Więcej informacji znajdziesz w rozdziale 21. „Zagadnienia wielodostępu, serwer plików, blokowanie”. Jet OLEDB:Engine Type Określenie silnika, który aktualnie jest wykorzystywany w celu uzyskania dostępu do danych. Jet OLEDB:Database Locking Mode Tryb używany podczas blokowania bazy danych. Więcej informacji w rozdziale 21., dotyczącym obsługi wielu użytkowników. Zauważ, że baza może być otwarta tylko w jednym trybie jednocześnie. Użytkownik, który jako pierwszy otwiera bazę, określa jej tryb blokowania. Jet OLEDB:Global Partial Bulk Ops Właściwość ta określa zachowanie Jet w przypadku błędu w masowych operacjach SQL DML. Może zostać unieważniona przez ustawienie właściwości Jet na OLEDB:Partial Bulk Ops. Jet OLEDB:Global Bulk Transactions Określa, czy masowe operacje SQL są wykonywane. Właściwość ta wskazuje ustawienie domyślne dla wszystkich operacji w aktualnym połączeniu. Oprócz właściwości umieszczonych w tabeli 7.1 silnik bazy danych Microsoft Jet posiada kilka opcji, których ustawienie określa zachowanie silnika. Opcje te często mają bezpośredni wpływ na jego wydajność. Domyślnie, po uruchomieniu Jet używane są wartości znajdujące się w rejestrze, w kluczu \HKEY_LOCAL_MACHINES\Software\Microsoft\Jet. Istnieje jednak możliwość tymczasowego unieważnienia tych ustawień. W przypadku ADO wartości te stanowią część ciągu połączenia. Stałe ciągu połączenia znajdują się w tabeli 7.2. Tabela 7.2. Opcje ciągu połączenia ADO DAO ADO dbPageTimeout Jet OLEDB:Page Timeout dbSharedAsyncDelay Jet OLEDB:Shared Async Delay dbExclusiveAsyncDelay Jet OLEDB:Exclusive Async Delay dbLockRetry Jet OLEDB:Lock Retry dbUserCommitSync Jet OLEDB:User Commit Sync dbImplicitCommitSync Jet OLEDB:Implicit Commit Sync dbMaxBufferSize Jet OLEDB:Max Buffer Size dbMaxLocksPerFile Jet OLEDB:Max Locks Per File dbLockDelay Jet OLEDB:Lock Delay dbRecycleLVs Jet OLEDB:Recycle Long-Valued Pages dbFlushTransactionTimeout Jet OLEDB:Flush transaction Timeout Poniższy fragment kodu powoduje otwarcie zabezpieczonej bazy, określając jej hasło i plik grupy roboczej: Dim conn As ADODB.Connection Set conn = New ADODB.Connection With conn .Provider = "Microsoft.Jet.OLE.DB.4.0" .ConnectionString = "data source= C:\databases\sample.mdb"&_ ";Jet OLEDB:Database Password=supersecret " & _ "; OLEDB:System database=" & _ "c:\windows\system\system.mdw" .Open End With CurrentProject.Connection Gdy chcesz uzyskać dostęp do aktualnej bazy poprzez kod ADO, Access umożliwia Ci pójście na skróty. Oddaje do Twojej dyspozycji odnośnik do obiektu Connection – CurrentProject.Connection. Używając tej składni, możesz z łatwością przydzielić aktualnej bazie obiekt Connection. Polecenie CurrentProject.Connection dostępne jest jedynie w kodzie VBA Accessa 2000. Użycie tej składni przedstawia poniższy fragment kodu: Dim conn As ADODB.Connection Set conn = CurrentProject.Connection CurrentProject.Connection pozwala zaoszczędzić czas, jeśli chcesz otworzyć zestaw rekordów. Możesz wykorzystać zdolność ADO do dynamicznego tworzenia połączenia poprzez polecenie Open: Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "Customers", CurrentProject.Connection Zalecamy ostrożność podczas korzystania z CurrentProject.Connection. Pamiętaj, że polecenie to nie może być używane w innym środowisku niż Access 2000. Jeśli zamierzasz wykorzystać swój kod w innej aplikacji niż Access (np. Visual Basic), do utworzenia połączenia musisz użyć dłuższej składni. Rola Microsoft Data Links w podłączaniu się do bazy danych Teraz, gdy obiekty ADO są podstawowym sposobem uzyskiwania dostępu do danych, twórcy Accessa uznali że programiści potrzebują standardowego sposobu obsługiwania, ładowania, otwierania i zarządzania informacjami o połączeniu OLE DB, przypominającego dawne narzędzie do zarządzania i administrowania sterownikami ODBC. Możliwość tę dają Microsoft Universal Data Links (UDL). Mechanizm UDL umożliwia zapisywanie informacji o połączeniu w pliku UDL, a następnie otwarcie obiektu Connection w ADO, na podstawie informacji zapisanych w tym pliku. Możliwość ta będzie bardzo przydatna, gdy chcesz przetestować podłączenie bazy danych do różnych komputerów bez zmiany kodu. Mechanizm Microsoft Universal Data Links składa się z: ? graficznego interfejsu użytkownika, służącego do tworzenia połączeń OLE DB; ? interfejsu automatyzacji. Zanim zaczniesz używać UDL w aplikacjach VB lub VBA, musisz najpierw je utworzyć. Tworzenie UDL nie jest skomplikowane. Uruchom Eksploratora Windows, z menu Plik wybierz Nowy, a następnie Microsoft Data Link (rysunek 7.1). Po utworzeniu pliku UDL kliknij go dwukrotnie, aby rozpocząć edycję. Przedstawiony na rysunku 7.2 pierwszy ekran zawiera listę wszystkich zainstalowanych na Twoim komputerze dostawców OLE DB. Wybierz jednego z nich i kliknij Dalej, aby przejść do zakładki Połączenie. Teraz możesz określić wszystkie, charakterystyczne dla dostawcy informacje dotyczące połączenia (rysunek 7.3). W naszym przykładzie użyliśmy dostawcy OLE DB dla Jet, więc musieliśmy określić ścieżkę dostępu, identyfikator użytkownika i hasło (gdybyśmy wybrali SQL Server, musielibyśmy podać nazwę serwera i bazy danych). Następna zakładka, Zaawansowane, służy do określenia właściwości dostawcy, które zazwyczaj ustalane są przez takie polecenia jak CommandTimeout. Ostatnia zakładka, Wszystkie, jest podsumowaniem wszystkich wybranych właściwości. Rysunek 7.1. Tworzenie nowego pliku UDL Rysunek 7.2. Wybór dostawcy OLE DB Rysunek 7.3. Wprowadzanie informacji o połączeniu Teraz, gdy utworzyłeś już plik UDL, możesz umieścić go w kodzie VBA, aby utworzyć w ADO obiekt Connection. Składnia jest prosta. Utwórz obiekt Connection, tak jak to zwykle robisz, i użyj obiektu Open. Następnie wskaż plik UDL za pomocą identyfikatora File Name: Dim conn As ADODB.Connection Set conn = New ADODB.Connection Conn.Open "File Name=c:\chapter7.udl;" Fragment kodu na wydruku 7.1 znajduje się w umieszczonym na dołączonej do książki płycie CD. Przedstawia on, jak utworzyć obiekt Connection oparty na pliku UDL, umieszczonym w folderze bazy danych Northwind. Łączysz się z bazą i wypełniasz okno za wartością tabeli Customers. Bardzo przydatną cechą tego kodu jest to, że jeśli będziesz chciał użyć bazy Northwind w wersji SQL, wystarczy zmienić właściwości pliku UDL i uruchomić kod ponownie. Wydruk 7.1. Użycie UDL w kodzie VBA Private Sub OpenViaLink() ' Procedura używa połączenia ADO, pobierając informacje ' o połączeniu z pliku Microsoft UDL ' Następnie otwierany jest recordset ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection Dim rst As ADODB.Recordset On Error GoTo Proc_Err Set conn = New ADODB.Connection ' Otwarcie połączenia poprzez plik UDL ' Pozwala to dynamicznie zmienić bazę danych, zmieniając ' plik UDL conn.Open "File Name=c:\chapter7.udl;" Set rst = New ADODB.Recordset ' Otwarcie wyniku wyrażenia SQL rst.Open "Select * From Customers", conn ' Przeglądamy wynik i wypisujemy wartości Do Until rst.EOF Debug.Print rst!CompanyName rst.MoveNext Loop ' Porządki rst.Close conn.Close Set rst = Nothing Set conn = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Zarządzanie plikami UDL Istnieją dwa sposoby zarządzania plikami UDL. Pierwszy – poprzez ich interfejs użytkownika. W Panelu sterowania systemu Windows znajduje się ikona Microsoft Data Links, która umożliwia wyświetlenie listy wszystkich plików UDL we wskazanym folderze (rysunek 7.4). Łatwiej jest jednak użyć Eksploratora Windows i bezpośrednio otworzyć żądany plik. Rysunek 7.4. Zarządzanie plikami UDL Programowe zarządzanie plikami UDL Ponieważ pliki UDL posiadają swój własny interfejs automatyzacji, możesz nimi zarządzać i kontrolować je programowo. Aby użyć UDL w kodzie VBA, ustaw odwołanie na typ biblioteki o nazwie Microsoft OLE DB Service Component 1.0 Type Library (rysunek 7.5). Rysunek 7.5. Ustawianie odnośnika na Microsoft OLE DB Service Component 1.0 Type Library Po ustawienie odwołania możesz rozpocząć zarządzanie plikami UDL. Dodatkowo możesz poprosić użytkownika o podanie informacji o połączeniu OLE DB poprzez okna dialogowe UDL. Możliwość ta jest przydatna w prototypowych aplikacjach lub wersjach demonstracyjnych produktów przeznaczonych dla użytkowników zaznajomionych z funkcjonowaniem Microsoft Data Links. Możesz tego dokonać, wykorzystując metodę PromptNew obiektu DataLinks. Kod na wydruku 7.2 prosi użytkownika o podanie informacji o połączeniu OLE DB poprzez okno dialogowe UDL, a następnie łączy się z bazą danych i otwiera zestaw rekordów. Wydruk 7.2. Programowe UDL Private Sub OpenUDLDialog() ' Procedura używa interfejsu automatyzacji ' UDL do utworzenia połączenia ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim strConnect As String Dim rst As ADODB.Recordset ' Odwołanie do Microsoft UDL Dim udl As MSDASC.DataLinks On Error GoTo Proc Err ' Tworzenie obiektu Data Link Set udl = New MSDASC.DataLinks ' Ustawienie obiektu connection na podstawie ' okna dialogowego nowego Data Link strConnect = udl.PromptNew Set rst = New ADODB.Recordset ' Otwarcie wyniku na podstawie ' danych wprowadzonych przez użytkownika ' do okna Data Link rst.Open "Select * From Customers", strConnect ' Wyświetl pierwszy rekord MsgBox rst!CompanyName Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Uzyskanie poprzez ADO dostępu do danych w bazach nierelacyjnych Nawiązując do omówionego w rozdziale 6. wykorzystania Accessa do komunikowania się z danymi nierelacyjnymi (jak np. Excel), ADO posiada kilka zaawansowanych opcji, które ułatwią Ci pracę z tym typem danych. Teraz przyjrzymy się opcjom: ? Lista użytkowników Jet. ? Tworzenie zestawów rekordów. ? Kształtowanie danych. Lista użytkowników Jet Dostawca OLE DB dla Jet umożliwi Ci otwarcie zestawu rekordów zawierającego nazwy użytkowników aktualnie zalogowanych do bazy, której nazwę określisz w połączeniu. Dzięki temu nie będziesz już musiał korzystać z dostarczanego z poprzednimi wersjami Jet narzędzia LDBView. Kod na wydruku 7.3 przedstawia sposób utworzenia zestawów rekordów z aktualnymi użytkownikami bazy danych. W listingu tym użyliśmy metody OpenSchema obiektu Connection z parametrem charakterystycznym dla aparatu JET/JOLT. Zauważ, że ADO nie podpowiada Ci żadnych stałych. Będziesz musiał ręcznie wprowadzić wartość GUID: ({947bb102-5d43-11d1-bdbf-00c04fb92675}). Pozostaje nam mieć nadzieję, że niedogodność ta zostanie poprawiona w kolejnej wersji obiektów ADO. Wydruk 7.3. Użycie listy użytkowników Sub UserRoster() ' Procedura używa listy użytkowników ' do sprawdzenia, kto jest zalogowany do bazy danych ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection Dim rst As ADODB.Recordset On Error GoTo Proc Err Set conn = New ADODB.Connection ' Otwarcie bazy danych With conn .Provider = "Microsoft.Jet.OLEDB.4.O" .ConnectionString = "data source=f:\employee.mdb" .Open End With ' Tworzenie wyniku opartego na ilości użytkowników ' bazy danych Set rst = conn.OpenSchema(adSchemaProviderSpecific, , _ "{947bb102-5d43-iidl-bdbf-00c04fb92675}") ' Dla każdego użytkownika wypisz nazwę jego komputera i ' inne informacje Do Until rst.EOF Debug.Print rst!COMPUTER_NAME Debug.Print rst!LOGIN_NAME Debug.Print rst!CONNECTED Debug.Print rst!SUSPECTED STATE rst.MoveNext Loop Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Tworzone zestawy rekordów Obiekty ADO stwarzają Ci możliwość tworzenia zestawów rekordów „z niczego”. Możesz teraz korzystać z metod Fields.Append i AddNew, aby dodawać pola i dane do zestawu rekordów. Technika ta nadaje się świetnie do tworzenia procedur pobierających dane z nierelacyjnych źródeł (np. folder z plikami) i zwracających zestaw rekordów. Dzięki ADO aplikacja może przez cały czas współpracować z zestawami rekordów, a kod aplikacji jest dużo prostszy. Poniższy przykład przedstawia sposób utworzenia zestawu rekordów zawierającego nazwy plików znajdujących się w określonym folderze. Jeśli umieścisz ten kod w module, będziesz go mógł użyć w wielu aplikacjach. Przykładowo, my wykorzystaliśmy go do sporządzenia listy wszystkich plików typu ZIP w katalogu serwera FTP, a następnie przejrzenia ich i utworzenia strony, z której można te pliki pobrać. Przewagą tej techniki nad dostawcą NT Active OLE DB jest fakt, iż działa ona w systemie Windows 95. Wydruk 7.4 przedstawia w jaki sposób można otworzyć zestaw rekordów oparty na liście nazw plików w folderze. Wydruk 7.4. Tworzenie zestawu rekordów z nierelacyjnych danych Sub CreatableRst_Files(strPath As String) 'Oto przykład tworzenia zestawu rekordów 'z danych nierelacyjnych 'Tworzy zestaw rekordów składający się z nazw i rozszerzeń plików 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim rst As ADODB.Recordset On Error GoTo Proc_Err Set rst = New ADODB.Recordset With rst 'Wykonaj operacje lokalne .CursorLocation = adUseClient 'Teraz dodaj pole .Fields.Append "FileName", adVarChar, 255, adFldRowID .Fields.Append "Extention", adChar, 3, adFldFixed 'Otwórz rst .Open , , adOpenStatic, adLockBatchOptimistic 'Upewnij się, że w ścieżce dostępu znajduje się znak \ If Right(strPath, 1) <> "\" Then strPath = strPath & "\" 'Pobierz listę wszystkich plików w folderze, a następnie 'dodaj je do zestawu rekordów strPath = Dir(strPath & "*.*", vbNormal) ' Nie umieszczaj wpisów . i .. Do While strPath > "" 'Teraz dodaj do rst nowy rekord .AddNew Array("FileName", "Extention"), _ Array(strPath, Right(strPath, 3)) strPath = Dir Loop .MoveFirst 'Wydrukuj pliki Do Until .EOF Debug.Print !FileName rst.MoveNext Loop End With Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Kształtowanie danych Umożliwienie przeglądania danych w zhierarchizowany sposób w obiektach ADO jest bardzo proste. Możesz użyć nowej zdolności ADO, o nazwie Data Shaping (ang. kształtowanie danych), aby przeglądać nadrzędne i podrzędne rekordy w jednym zestawie. Możesz użyć dostawcy MSDataShape OLE DB do tworzenia hierarchii opartych na relacjach i hierarchii grupowania. Tworzenie tego typu hierarchicznych zestawów rekordów może ułatwić dość pracochłonną obróbkę hierarchicznych danych. Przykładowo, na rysunku 7.6 znajduje się grupowa hierarchia wszystkich zamówień klientów z bazy Northwind, przeglądana w nowej siatce o nazwie Microsoft Hierarchical FlexGrid (wersja OLAP popularnej FlexGrid). Formant ten dołączony jest do pakietu Office 2000 w wersji Developer Edition oraz do Visual Basic 6 (nasze wartości i listingi napisane zostały w VB 6 i używają bazy danych Accessa jako źródła danych). Zwróć uwagę na znak plus znajdujący się przy każdym z rekordów. Umożliwia on rozszerzanie każdego z rekordów i przeglądanie jego szczegółów, co przedstawia rysunek 7.7. Zanim powstał dostawca MSDataShape OLE DB, utworzenie takiej siatki wymagało napisania wielu linijek kodu. Rysunek 7.6. Zestaw rekordów uzyskany poprzez dostawcę MSDataShape OLE DB w Visual Basic Rysunek 7.7. Zestaw rekordów GrupujWedług w Visual Basic Wydruk 7.5. Tworzenie rekordu z ukształtowanymi danymi i wypełnianie siatki MSHFlexGrid w VB Sub CubeGroupHierarchy() 'Wypełnij formant MSFLEXGRID 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston 'Kod do wypełnienia zestawu rekordów Dim rst As ADODB.Recordset Dim strConnect As String Set rst = New ADODB.Recordset 'Ustaw właściwości połączenia 'Każ ADO użyć dostarczyciela OLE DB dla Data Shaping 'Następnie podłącz wbudowanego dostarczyciela OLE DB do 'wybranego źródła danych strConnect = "Provider=MSDataShape" & _ ";data provider=Microsoft.Jet.OLEDB.4.0" & _ ";data source=" & App.path & "\sample.mdb" 'Wprowadź SQL Data Shape rst.Source = "shape {Select customerid, " & _ "Region from Customers} rst1 " & _ "COMPUTE COUNT (rst1.customerid) AS CustCount, rst1 By Region " rst.ActiveConnection = strConnect rst.Open , , adOpenStatic, adLockBatchOptimistic 'Pokaż RST Set frmADO.MSHFlexGrid1.Recordset = rst End Sub Jak widać w tym fragmencie kodu, musisz użyć specjalnej, powiązanej z Data Shaping składni SQL. Kompletną listę zastosowań tej składni znajdziesz w dostarczanym wraz z Visual Basic 6 i pakietem Office Developer 2000 dokumentacji MSDN oraz na stronie WWW pod adresem http://www.microsoft.com/data. Możesz również użyć tego kodu do operacji Data Shaping i przeniesienia danych do programu Microsoft Excel. Kod na wydruku 7.6 przedstawia sposób, jak za pomocą poprzedniego przykładu przenieść dane do arkusza programu Excel. Wydruk 7.6. Użycie Data Shaping w programie Microsoft Excel Sub CUBRelation() 'Użycie OLAP z Microsoft Excel 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim rst As ADODB.Recordset Dim strConnect As String Set rst = New ADODB.Recordset 'Ustaw właściwości połączenia 'Nakaż ADO użycie dostarczyciela OLE DB dla Data Shaping 'Następnie podłącz wbudowanego dostarczyciela OLE DB do 'wybranego źródła danych strConnect = "Provider=MSDataShape;" & _ ";data provider=Microsoft.Jet.OLEDB.4.0" & _ ";data source=C:\sample.mdb" 'Wprowadź SQL Data Shape rst.Source = "shape {Select * from customers where Customerid='ALFKI'}"&_ " Append " & _ "({Select * From Orders} As rsOrders " & _ "RELATE customerid to customerid)" rst.ActiveConnection = strConnect rst.Open , , adOpenStatic, adLockBatchOptimistic 'Pokaż RST ShowRSTinExcel rst End Sub Sub ShowRSTinExcel(rst As ADODB.Recordset, _ Optional blnSKipClear As Boolean = False) Dim rstChild As ADODB.Recordset Dim col As ADODB.Field Dim intCurrentColumn As Integer Dim intCurrentRow As Integer If Not blnSKipClear Then 'Clear out the cells Cells.Select Selection.ClearContents End If Do Until rst.EOF intCurrentColumn = intCurrentColumn + 1 If Not blnSKipClear Then intCurrentRow = 1 Else intCurrentRow = 2 End If For Each col In rst.Fields If col.Type <> adChapter Then Cells(intCurrentColumn, intCurrentRow) = _ col.Name & ": " & col.Value Else Set rstChild = col.Value ShowRSTinExcel rstChild, True End If intCurrentRow = intCurrentRow + 1 Next rst.MoveNext Loop Cells(1, 1).Select End Sub Zaawansowana obróbka danych przy użyciu ADO W ostatnim rozdziale pokazaliśmy, jak tworzyć zestawy rekordów zawierające dane i jak korzystać z obiektów Command. W tej części pokażemy kilka dodatkowych możliwości obiektów ADO. Przyjrzymy się: ? Modyfikowaniu danych w zestawie rekordów. ? Trwałym zestawom rekordów. Modyfikowanie danych w zestawie rekordów Aby modyfikować dane w zestawie rekordów, musisz jedynie przejść do niego i rozpocząć edycję. Po przejściu do kolejnego rekordu lub użyciu metody Call dokonane przez Ciebie zmiany zostaną zapisane. Jest to duży krok naprzód w porównaniu z obiektami DAO, gdzie musiałeś najpierw użyć polecenia Edit, a następnie obowiązkowo użyć polecenia Update. Kod na wydruku 7.7 przedstawia, w jaki sposób można dokonać edycji danych. Wydruk 7.7. Edycja rekordu Sub Editrecords() 'Procedura edycji danych 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim rst As ADODB.Recordset Dim strSQL As String On Error GoTo Proc Err ' Tworzenie obiektu recordset Set rst = New ADODB.Recordset ' Wpisz tu wyrażenie SQL zwracające potrzebne dane strSQL = "Select * From Customers Where CustomerID='Anton'" ' Otwarcie wyniku za pomocą kursora keyset rst.Open strSQL, CurrentProject.Connection, _ adOpenKeyset, adLockOptimistic ' Zmiana wiersza rst!CompanyName = "Nowa nazwa" ' Użycie metody Update lub MoveNext rst.Update Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Szybciej jest otworzyć zestaw rekordów bazujący na wyrażeniu SQL wymagającym klucza podstawowego niż otwierać całą tabelę i w niej szukać żądanego rekordu. Ponieważ zmiany dokonywane w zestawie rekordów uwzględniane są bez użycia polecenia Update, jedynie przez przejście do kolejnego rekordu, zalecamy ostrożność podczas edycji danych. Dodawanie rekordu Dodawanie rekordu przebiega w prawie identyczny sposób jak edycja. Musisz otworzyć zestaw rekordów i użyć metody AddNew. Tak samo jak w przypadku Edit tak i w przypadku Update zastosowanie mają te same zasady. Po dodaniu rekordu będziesz się znajdował w aktualnym rekordzie. Wydruk 7.8 zawiera przykład dodawania rekordu do tabeli. Wydruk 7.8. Dodawanie rekordu do tabeli Sub Addrecords() ' Procedura dodaje nowy rekord do tabeli 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim rst As ADODB.Recordset On Error GoTo Proc_Err ' Tworzenie obiektu recordset Set rst = New ADODB.Recordset With rst ' Otwarcie tabeli .Open "Authors", CurrentProject.Connection, _ adOpenDynamic, adLockOptimistic, adCmdTableDirect ' Teraz należy użyć AddNew .AddNew !AuthorFirstName = "Mike" !AuthorLastName = "Smith" .Update ' Po dodaniu rekordem bieżącym jest nowy rekord MsgBox "ID nowego autora: " & !AuthorID End With Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Być może zauważyłeś, że otwarłeś tabelę ze stałą adCmdTableDirect. Jeśli użyjesz tej stałej z typem kursora adOpenDynaset i blokowaniem optymistycznym, osiągniesz taki sam efekt jak przy użyciu polecenia dbOpenTable w DAO. Tabela 7.3 zawiera wszystkie opcje kursorów i blokowania ADO oraz ich odpowiedniki w DAO. Tabela 7.3. Kombinacje obiektów ADO dla Accessa Typ kursora Opcje i typy blokowania Odpowiednik w DAO adOpenForwardOnly adLockReadOnly dbOpenSnapShot dbForwardOnly AdOpenKeySet adLockReadOnly Brak odpowiednika AdOpenKeySet adLockPessimistic dnOpenDynaset Tabela 7.3. Kombinacje obiektów ADO dla Accessa (ciąg dalszy) Typ kursora Opcje i typy blokowania Odpowiednik w DAO AdOpenKeySet adLockOptimistic dnOpenDynaset AdOpenKeySet adLockBatchOptimistic dnOpenDynaset AdOpenStatic adLockReadOnly dnOpenDynaset adOpenDynamic adLockOptimistic adCmdTableDirect dbOpenTable Trwałe zestawy rekordów Dla tych z was, którzy muszą również zadbać o obsługę użytkowników nie podłączonych do sieci, pojęcie trwałości rekordów to fantastyczny podarunek od firmy z Redmond. Teraz masz bowiem możliwość zapisania zestawu rekordów na dysku i jego obróbkę w aplikacji VB lub VBA. Później możesz ten zestaw ponownie włączyć do bazy. Aby tego dokonać, otwórz zestaw rekordów ADO z typem blokowania adLockBatchOptimistic i używając kursora client. Następnie użyj polecenia Save obiektu Recordset. Musisz określić nazwę pliku i format, w jakim ma być zapisany. ADO oddaje do Twojej dyspozycji następujące możliwości: ? adPersistADTG; ? adPersistXML. Jeśli wybierzesz format adPersistADTG lub adPersistXML, będziesz mógł później z łatwością otworzyć ten plik w ADO. Wydruk 7.9 przedstawia, jak otworzyć zestaw rekordów, zmienić rekord, zapisać zmiany do pliku, otworzyć go ponownie i włączyć z powrotem do bazy. Wydruk 7.9. Zapisywanie zestawu rekordów na dysku, jego ponowne otwarcie i ponowne włączenie do bazy danych Sub RstPersistence Save() ' Przykład pobrania wyniku, odłączenia od bazy danych ' zapisu na dysk a następnie synchronizacji z bazą ' Synchronizacja zachodzi w RstPersistence_Open ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim strSOL As String Dim strMsg As String Dim strNewValue As String Dim conn As ADODB.Connection Dim rst As ADODB.Recordset On Error GoTo Proc Err strSQL = "Select * From Customers Where CustomerID='ALFKI'" Set conn = New ADODB.Connection With conn .Provider = "Microsoft.Jet.OLEDB.4.O" .ConnectionString = "data source=c:\sample.mdb" .Open End With Set rst = New ADODB.Recordset ' Należy użyć kursora po stronie klienta rst.CursorLocation = adUseClient rst.Open strSQL, conn, adOpenStatic, adLockBatchOptimistic ' Pozwól użytkownikowi zmienić dane, pokazując dane bieżące strMsg = "Proszę wprowadzić nową nazwę firmy dla: " & _ rst!CompanyName & vbNewLine & _ "ID klienta=" & rst!CustomerID ' Pobierz nową nazwę strNewValue = InputBox(strMsg) ' Zmień rekord na komputerze klienta i zapisz na dysku ' Nie zmienia to danych w bazie danych rst.Update "CompanyName", strNewValue ' Zmiana została wprowadzona do recordsetu klienta On Error Resume Next ' Usuń istniejący plik Kill "c:\hcado.dat" On Error GoTo Proc_Err ' Zapisz recordset na dysku rst.Save "c:\hcado.dat", adPersistADTG rst.Close Set rst = Nothing MsgBox "Zapisane do: c:\hcado.dat", vbInformation Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Sub RstPersiStence Open() ' Przykład pobrania wyniku, odłączenia od bazy danych ' zapisu na dysk a następnie synchronizacji z bazą ' Zapis był wykonany w RstPersistence_Save ' Tu wykonywana jest synchronizacja ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim conn As ADODB.Connection Dim rst As ADODB.Recordset Dim strSQL As String Dim strMsg As String On Error GoTo Proc Err strSQL = "Select * From Customers Where CustomerID='ALFKI'" ' Pobranie nowego recordset z dysku Set rst = New ADODB.Recordset rst.Open "c:\hcado.dat", , adOpenStatic, adLockBatchOptimistic, _ adCmdFile ' Pokazanie danych z bazy danych i z dysku strMsg = "Wartości w bazie danych: " & _ rst!CompanyName.OriginalValue strMsg = strMsg & vbNewLine & _ "Wartości na dysku: " & rst!CompanyName ' Wyświetl wartości MsgBox strMsg, vbInformation, "Wartości z bazy i z dysku" ' Teraz uaktualnimy bazę danych wartościami z dysku ' Trzeba ponownie podłączyć się do bazy Set conn = New ADODB.Connection With conn .Provider = "Microsoft.Jet.OLEDB.4.O" .ConnectionString = "data source=c:\sample.mdb" .Open End With ' Powtórne przyłączenie recordsetu do bazy danych i synchronizacja rst.Active0onnection = conn rst.UpdateBatch MsgBox "Baza danych zsynchronizowana !", vbInformation Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Definiowanie danych przy użyciu ADOX Korzystając z obiektów ADO, możesz z łatwością dokonywać definiowania danych. Aby tworzyć i modyfikować tabele, kwerendy i inne obiekty związane z danymi, jak na przykład indeksy, musisz skorzystać ze specjalnej biblioteki ADO o nazwie ADOX. Aby użyć ADOX, musisz ustawić odnośnik na Microsoft ADO Ext. 2.1 For DDL and Security, wybierając z menu Tools pozycję References (rysunek 7.8). Rysunek 7.8. Microsoft ADO Ext. 2.1 For DDL and Security Gdy ustawiłeś już odnośnik, jesteś gotów do korzystania z ADOX. Obiekt Catalog Gdy korzystasz z ADOX, wszystko co robisz związane jest z obiektem Catalog. Catalog oznacza bazę danych. Pracując w Accessie, musisz jedynie ustawić właściwość tego obiektu, ActiveConnection, na prawidłowy obiekt Command. Dim cat As ADOX.Catalog Set cat = New ADOx.Catalog 'Wskaż obiektowi Catalog 'aktualną bazę danych cat.ActiveConnection = CurrentProject.Connection Tworzenie bazy danych Aby utworzyć nową, pustą bazę danych przy użyciu ADOX, musisz użyć polecenia Create obiektu Catalog i podać ścieżkę dostępu do nowej bazy (wydruk 7.10). Wydruk 7.10. Tworzenie bazy danych przy użyciu ADOX Sub CreateOataBase() ' Procedura tworzy nową bazę danych przy użyciu ADOX 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston ' Obiekt catalog w ADOX Dim cat As ADOx.Catalog On Error GoTo Proc_Err Set cat = New ADOx.Catalog cat.Create "provider=Microsoft.JET.OLEDB.4.0;" & _ "data source=C:\newdb.mdb" MsgBox "Baza danyh utworzona!", vbInformation Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Tworzenie tabel i pól Aby utworzyć tabelę i jej pola, możesz utworzyć obiekt ADOX o nazwie table i dołączyć do niego kolumny (wydruk 7.11). Wydruk 7.11. Tworzenie tabel i pól Sub CreateTable_JOLT4O() ' Przykład tworzy tabelę i jej pola w bieżącej bazie danych 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston ' Obiekty ADOX Dim cat As ADOx.Catalog Dim tbl As ADOx.Table On Error GoTo Proc_Err Set cat = New ADOx.Catalog ' Wskazanie na obiekt Catalog bieżącej bazy danych cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOx.Table ' Tworzy tabelę With tbl .Name = "Customer_ADO" .Columns.Append "CustomerID", adInteger .Columns.Append "Name_Prefix", adWChar, 25. .Columns.Append "Name_First", adWChar, 2 .Columns.Append "Name_Last", adWChar, 50 End With cat.Tables.Append tbl Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Tworzenie dołączonej tabeli Aby utworzyć w Accessie dołączoną tabelę, musisz utworzyć tabelę i nie dołączać do niej żadnych pól, a następnie ustawić dwie właściwości: ? Jet OLE DB:Link Datasource; ? JET OLE DB:Remote Table Name. Jako Link Datasource podaj ścieżkę dostępu do bazy danych, do której chcesz się dołączyć. Jako Remote Table Name ustaw nazwę tej bazy. Cały przykład znajduje się na wydruku 7.12. Wydruk 7.12. Tworzenie dołączonej tabeli Sub CreateAttachedJetTable() ' Tworzy tabelę dołączoną ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim cat As ADOx.Catalog Dim tbl As ADOx.Table Set cat = New ADOx.Catalog ' Otwarcie katalogu cat.Active0onnection = CurrentProject.Connection Set tbl = New ADOx.Table ' Tworzenie nowej tabeli tbl.Name = "Customers_Połączona" ' Skrót dla tworzenia tabel Set tbl.ParentCatalog = cat ' Ustawienie właściwości połączenia tbl.Properties("Jet OLEDB:Link Datasource") = _ "F:\backend\datafile.mdb" tbl.Properties("Jet OLEDB:Remote Table Name") = "Customers" ' Dołącz tabelę do kolekcji tabel cat.Tables.Append tbl Set cat = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Ustawianie właściwości pola W ADOX, po utworzeniu pola, możesz użyć obiektu Column, aby ustawić właściwości charakterystyczne dla tego pola. Przykładowo, możesz ustawić typ pola na Autonumerowanie, nadając właściwości AutoIncrement wartość True: Dim col As ADOX.Column 'Wskaż obiektowi Column 'pole CustomerID Set col = tbl.Columns("CustomerID") 'Ustaw Column na pole typu Autonumerowanie col.Properties("Autincrement") = True Istnieją inne właściwości, które możesz ustawić dla obiektu Column. Umieściliśmy je w tabeli 7.4 wraz z ich odpowiednikami w DAO. Tabela 7.4. Właściwości obiektu Field Pole DAO Obiekt Column w ADOX Właściwość Wartość Właściwość Wartość Attributes dbAutoIncrField AutoIncrement True Attributes dbFixedField ColumnAttributes adColFixed Attributes dbHyperlinkField Jet OLEDB:Hyperlink True Attributes dbSystemField Attributes dbVariableField ColumnAttributes Not adColFixed Tworzenie indeksu Tworząc indeks w ADOX, będziesz musiał użyć klucza obiektu. Po jego utworzeniu musisz dołączyć do niego pole, a następnie określić, czy ma to być klucz podstawowy czy unikatowy i jaka ma być kolejność sortowania: Set idx = New Adox.Index 'Teraz ustalamy, że będzie to klucz podstawowy, 'sortowany w kolejności malejącej With idx .Name = 'Primary Key' .Columns.Append "CustomerID" .Columns("CustomerID").SortOrder = adSortDescending .IndexNulls = adIndexNullsDisallow .PrimaryKey = True End With 'Dołączenie indeksu do tabeli tbl.Indexes.Append idx Właściwość IndexNulls ustawiona jest domyślnie na adIndexNullsDisallow, co oznacza, że wartości Null nie są w indeksie dopuszczalne i w przypadku, gdy pole w indeksie będzie taką wartość zawierać, żaden wpis do indeksu nie zostanie dokonany. W tabeli 7.5 znajdują się wartości akceptowane przez właściwość IndexNulls, wraz z ich odpowiednikami w DAO. Tabela 7.5. Wartości dla właściwości IndexNulls DAO ADOX Opis Wymagane Ignore Nulls Index Nulls True False AdIndexNullsDisallow Wartość Null nie jest akceptowana w polu indeks; wpis do indeksu nie zostanie dokonany False True AdIndexNullsIgnore Wartość Null dopuszczona w polu indeks; wpis do indeksu nie zostanie dokonany False False AdIndexNullsIgnoreAny Wartość Null dopuszczona w polu indeks; wpis do indeksu zostanie dokonany Kod na wydruku 7.13 łączy te wszystkie przykłady, tworząc tabelę pola Autonumerowanie i indeks klucza głównego w tej tabeli. Wydruk 7.13. Tworzenie tabeli z polem Autonumerowanie i indeksem klucza głównego Sub CreateCreateAutoNumberrPK() 'Przykład ten tworzy tabelę 'i pola w aktualnej bazie danych 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston 'Obiekty ADOX Dim cat As ADOX.Catalog Dim tbl As New ADOX.Table Dim idx As ADOX.Index On Error GoTo Proc_Err Set cat = New ADOX.Catalog 'Wskaż obiektowi Catalog 'aktualną bazę danych cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOX.Table 'Teraz tworzymy tabelę With tbl .Name = "Customer_ADO" .ParentCatalog = cat .Columns.Append "CustomerID", adInteger 'Ustaw pole Autonumerowanie .Columns("CustomerID").Properties("Autoincrement") = True .Columns.Append "Name_Prefix", adWChar, 25 .Columns.Append "Name_First", adWChar, 25 .Columns.Append "Name_Last", adWChar, 50 End With 'Dołącz tabelę do obiektu catalog cat.Tables.Append tbl 'Teraz tworzymy obiekt index Set idx = New ADOX.Index 'Teraz ustawiamy klucz 'jako klucz podstawowy i 'sortujemy go w porządku malejącym With idx .Name = "PrimaryKey" .Columns.Append "CustomerID" .Columns("CustomerID").SortOrder = adSortDescending .IndexNulls = adIndexNullsDisallow .PrimaryKey = True End With 'Dołączamy indeks do tabeli tbl.Indexes.Append idx 'Sprzątamy Set cat = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Tworzenie relacji w ADOX Aby utworzyć relację w ADOX, musisz utworzyć obiekt klucza, określić jego właściwości, a następnie dołączyć ten klucz do obiektu Table. Użyj następującej składni: Cat.Tables("Products").Keys.Append key Kod na wydruku 7.14 wykonuje wszystkie te czynności oraz tworzy relacje. Wydruk 7.14. Tworzenie relacji Sub CreateForeignKey() 'Tworzenie relacji między tabelami 'Products i Categories w bazie Northwind 'Z książki "Access 2000 Księga eksperta" (Helion) 'Autorzy: Forte, Howe, Ralston Dim cat As ADOX.Catalog Dim key As ADOX.key On Error GoTo Proc_Err 'Tworzenie obiektów ADOx Set cat = New ADOX.Catalog Set key = New ADOX.key 'Otwarcie obiektu katalog na aktualną bazę danych cat.ActiveConnection = CurrentProject.Connection 'Ustawienie właściwości nowego obiektu Key With key 'Nazwa obiektu Key w bazie 'musi być unikatowa .Name = "CategoriesProducts" 'Określenie rodzaju klucza .Type = adKeyForeign 'Określenie strony JEDEN relacji jeden-do-wielu .RelatedTable = "Categories" 'Określenie strony WIELU .Columns.Append "CategoryID" 'Pole "jeden" w tabeli po stronie "jeden" .Columns("CategoryID").RelatedColumn = "CategoryID" 'Określenie aktualizowania kaskadowego .UpdateRule = adRICascade End With 'Teraz określ tabele po stronie "wielu" 'i dołącz do niej nowy obiekt Key cat.Tables("Products").Keys.Append key Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Tworzenie kwerend w ADOX Aby utworzyć kwerendę w ADOX, musisz użyć pustego obiektu Command i ustawić jego właściwość CommandText, a następnie dołączyć go do aktualnego obiektu catalog: cmd.CommandText = "Select * FROM Categories" "Dołącz kwerendę do zbioru cat.Views.Append "qryCategories", cmd Gdy odnosisz się do kwerendy w Accessie, musisz pamiętać, że Microsoft Jet 4.0 zarządza wszystkimi tabelami, kwerendami, polami i indeksami za Ciebie. Microsoft Jet definiuje kwerendy Accessa na dwa sposoby: ? widoki; ? procedury. Przez widok rozumiemy zwracającą wiersze, nieparametryczną kwerendę, podczas gdy procedura oznacza wszystkie inne kwerendy. Tworzenie widoku Microsoft Jet zajmie się za Ciebie definiowaniem kwerendy. By utworzyć widok, należy utworzyć kwerendę poprzez obiekt Command (wydruk 7.15). Wydruk 7.15. Tworzenie widoku w ADOX Sub CreateView() ' Tworzenie nowej kwerendy (widoku) ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim cat As ADOx.Catalog Dim cmd As ApODB.Command Set cat = New ADOx.Catalog Set cmd = New ADODB.Command ' Otwarcie katalogu cat.ActiveConnection = CurrentProject.Connection ' Tworzenie kwerendy cmd.CommandText = "Select * FROM Categories" ' Dołączenie kwerendy do kolekcji cat.Views.Append "qryCategories", cmd Set cat = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Tworzenie procedury Tworzenie procedury jest równie proste jak tworzenie widoku. Wystarczy zdefiniować właściwość Commandtext i dołączyć go do obiektu catalog (wydruk 7.16). Wydruk 7.16. Tworzenie procedury Sub CreateProcedure() ' Tworzenie kwerendy (procedury) ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim cat As ADOx.Catalog Dim cmd As ADODB.Command Set cat = New ADOx.Catalog Set cmd = New ADODB.Command ' Otwarcie katalogu cat.ActiveConnection = CurrentProject.Connection 'Create the komendy cmd.CommandText = "Parameters [@Region] Text;" & _ "Select * from Employees where Region = [@Region]" ' Tworzenie procedury cat.Procedures.Append "qryEmployeesRegion", cmd Set cat = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Modyfikowanie wyrażenia SQL kwerendy Aby zmodyfikować wyrażenie SQL kwerendy, musisz najpierw utworzyć obiekt command oparty na aktualnej kwerendzie w bazie danych, a następnie zmodyfikować właściwość commandtext i zresetować obiekt command (wydruk 7.17). Wydruk 7.17. Zmiana wyrażenia SQL Sub Modify0uerySQL() ' Zmiana wyrażenia SQL kwerendy ' Z książki "Access 2000 Księga eksperta" (Helion) ' Autorzy: Forte, Howe, Ralston Dim cat As ADOx.Catalog Dim cmd As ADODB.Command On Error GoTo Proc Err Set cat = New ADOx.Catalog Set cmd = New ADODB.Command ' Otwarcie katalogu cat.ActiveConnection = CurrentProject.Connection ' Pobranie kwerendy z bazy danych Set cmd = cat.Procedures("qryEmployeesRegion").Command ' Zmiana wyrażenia SQL cmd.CommandText = "Parameters [forms]![frmOrder]![txtRegion] Text;" &_ "Select * from Employees " & _ "Where Region = [forms]![frmOrder]![txtRegion] " ' Zapis zmienionej kwerendy Set cat.Procedures("qryEmployeesRegion").Command = cmd Set cat = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Zauważysz, że w kodzie ADO znajdującym się na wydruku 7.17 ustawienie właściwości Command obiektu Procedure na zmodyfikowany obiekt Command powoduje zapisanie zmian. Gdybyśmy nie umieścili tego ostatniego kroku, zmiany nie zostałyby umieszczone na stałe w bazie danych. Różnica ta wynika z faktu, iż obiekty Command zostały zaprojektowane jako tymczasowe. Fakt ten ma duże znaczenie, gdyż w DAO obiekty Querydefs uważane były za trwałe. Może Ci się wydawać, że poniższe fragmenty kodu ADO są równoznaczne: Set cmd = cat.Procedures("qryEmployeesRegion").Command cmd.CommandText = "Parameters [@Region] Text;" & _ "Select * from Employees where Region = [@Region]" Set cat.Procedures("qryEmployeesRegion").Command = cmd oraz cat.Procedures("qryEmployeesRegion").CommandText = _ "Parameters [@Region] text;" & _ "Select * from Employees where Region = [@Region] " Mimo iż pozornie wygląda na to, że działają podobnie, drugi fragment kodu nie spowoduje rzeczywistej aktualizacji kwerendy w bazie. W drugim przykładzie możesz użyć obiektu Command z jego nowym SQL w kodzie VBA. Jednakże kiedy zakończysz pracę, zmiany w SQL nie zostaną zapisane w bazie. W pierwszym przypadku, ponieważ nakazujesz zapisanie cmd, zmiany zostaną uwzględnione w bazie danych. Część III Interfejs użytkownika W tej części: ? Projektowanie formularza. ? Rozbudowa formularzy przy użyciu formantów ActiveX. ? Raporty. Rozdział 8. Projektowanie formularza W tym rozdziale: ? Właściwości formularza. ? Formanty formularza w Accessie. Formularze decydują o powodzeniu tworzonej aplikacji. Nie dlatego, że są one sercem aplikacji Accessa, lecz dlatego, że to na pracy z nimi użytkownicy spędzają najwięcej czasu. Dlatego też Twórcy programu dołożyli wszelkich starań, by formularze w Accessie były jednocześnie proste i potężne. W rozdziale tym nie zamierzamy wyjaśnić wszystkich szczegółów dotyczących tworzenia formularzy w Accessie (temat ten jest bardzo obszerny i istnieje wiele dobrych książek, zarówno dla początkujących jak i doświadczonych użytkowników). Aby przekazać Ci jak najwięcej szczegółów zanadto się nie rozpisując, skupimy się na niektórych ustawieniach i właściwościach formularza, które mogą ułatwić proces tworzenia oraz pomóc w uzyskaniu rozbudowanego zestawu funkcji. Następnie przyjrzymy się zastosowaniu niektórych formantów Accessa i pokażemy, jak możesz wykorzystać je w tworzeniu formularzy będących czymś więcej niż tylko narzędziem do wprowadzania danych. Po przeczytaniu tego rozdziału będziesz w stanie projektować formularze, które nie tylko będą dostarczać użytkownikom szerokiego zestawu funkcji, ale jednocześnie będą łatwe w obsłudze i estetyczne. Na początku tego rozdziału przyjrzymy się właściwościom i ustawieniom w Accessie 2000. Następnie przejdziemy do bardziej zaawansowanych formantów w Przyborniku Accessa, a zwłaszcza pól listy i pól wyboru. Później przyjrzymy się użyciu przycisków polecenia i przycisków opcji, a następnie pokażemy, jak zwiększyć funkcjonalność formularza i ograniczyć ilość stron i niepotrzebnych formantów, wykorzystując do tego celu podformularze. Na koniec przyjrzymy się dołączonym do pakietu Office 2000 w wersji Developer Edition formantom ActiveX oraz sposobom ich wykorzystania w celu powiększenia zestawu funkcji aplikacji. Właściwości formularza Określając właściwości formularza w Accessie 2000, możesz wybierać spośród 81 zdefiniowanych właściwości, znajdujących się na zakładce Właściwości (rysunek 8.1). Dokładne ich omówienie zajęłoby całą książkę. My skupiliśmy się na tych właściwościach, które będą miały wpływ na Twoją pracę jako programisty. Rysunek 8.1. Okno dialogowe Właściwości formularza Zakładka Dane Formularze w Accessie 2000 są ściśle powiązane z ukrywającymi się za nimi danymi. Możesz bez trudu utworzyć formularz i rozpocząć wprowadzanie danych bez pisania ani jednej linii kodu. Możesz to zrobić dzięki właściwościom znajdującym się na zakładce Dane, które jak sama nazwa wskazuje opisują sposób, w jaki formularz powinien przedstawiać i współpracować z danymi. Źródło rekordów To chyba najczęściej wykorzystywana właściwość formularza. Dzięki niej możesz powiązać formularz z dowolną tabelą, kwerendą, wyrażeniem SQL lub czymkolwiek innym. Właściwość ta, zależnie od potrzeb, może być określana podczas projektowania lub też uruchamiania formularza. Jeśli nie określisz źródła rekordów podczas projektowania, nie będziesz mógł z nim powiązać pojedynczych pól formularza. Edycja dozwolona Po ustawieniu tej właściwości na Tak użytkownicy będą mogli modyfikować dane na formularzu. Inaczej będzie w przypadku ustawienia Nie. Dzięki temu można w prosty sposób utworzyć formularz tylko do odczytu. Usuwanie dozwolone Po ustawieniu tej właściwości na Tak użytkownicy będą mogli usuwać rekordy z formularza. Dzięki tej właściwości masz kontrolę nad tym, którzy z użytkowników mogą usuwać rekordy z bazy danych. Dodawanie dozwolone Po ustawieniu tej właściwości na Nie użytkownicy nie będą mogli dodawać do bazy nowych rekordów. Rozwiązanie to jest wygodne w sytuacji, gdy wyświetlasz rezultaty kwerendy w widoku arkusza danych, ale nie chcesz, by użytkownicy dodawali na końcu zestawu rezultatów nowe rekordy. Wprowadzanie danych Ustawienie tej właściwości na Tak spowoduje, iż użytkownicy będą mieli możliwość dodawania nowych rekordów, jednakże bez możliwości przeglądania już istniejących. Filtry dozwolone, Filtr, Uporządkuj według Właściwości te umożliwiają zastrzeżenie określonego zestawu rekordów w danym formularzu poprzez użycie warunku WHERE we właściwości Filtr lub kolejności sortowania we właściwości Uporządkuj według. Właściwość Filtry dozwolone nakazuje (bądź nie) Accessowi czytanie tych wartości podczas otwierania formularza. Generalnie, użycie tych właściwości może okazać się nieprzydatne. Używając kwerendy we właściwości Źródło rekordów, możesz za jednym razem określić parametry i kolejność sortowania. Co więcej, we właściwości Źródło rekordów możesz skorzystać z optymalizowanych kwerend, co jeszcze bardziej przyśpiesza pracę. Zakładka Format Formularze są tymi obiektami, które użytkownik ogląda. Może nie są najważniejszą częścią aplikacji, jednak użytkownicy o tym nie wiedzą. Wyrabiają sobie opinię na temat aplikacji właśnie na podstawie formularzy. Sposób, w jaki wyglądają, zachowują się i ułatwiają (bądź utrudniają) codzienne zadania użytkownikom jest bardzo ważny zarówno dla tych ostatnich, jak i dla Ciebie. Ustawienie właściwości związanych z formatem umożliwi kontrolowanie wyglądu tworzonych formularzy. Widok domyślny Ustawienie tej właściwości nakazuje Accessowi otwarcie formularza w określony sposób. Masz do wyboru następujące możliwości: ? Formularz pojedynczy – wyświetla rekordy pojedynczo. ? Formularze ciągłe – wyświetla, wiele rekordów, każdy z nich we własnej kopii formularza w części szczegółowej. ? Arkusz danych – podobnie jak arkusz kalkulacyjny wyświetla dane w wierszach i kolumnach. Dostępne widoki Ustawiając tę właściwość, możesz ograniczyć ilość sposobów, na jakie użytkownicy będą przeglądać dane. Opcja ta jest bardzo przydatna, gdy chcesz, aby użytkownicy widzieli tylko jeden rekord jednocześnie lub jedynie dane w arkuszu danych. Masz do wyboru następujące ustawienia: ? Formularz. ? Arkusz danych. ? Oba. Paski przewijania Właściwość ta umożliwia Ci wyłączenie lub włączenie pionowego i poziomego paska przewijania w formularzu. Selektory rekordów Właściwość ta włącza lub wyłącza znajdujące się po lewej stronie formularza selektory rekordów. W przypadku pojedynczych formularzy właściwość ta jest zazwyczaj wyłączona. Dobrze jest jednak ją włączyć w formularzach ciągłych i arkuszu danych. Przyciski nawigacyjne Jeśli chcesz, by Access zajął się przemieszczaniem się po rekordach, ustaw tę właściwość na Tak. Jeśli chcesz tę operację wykonywać własnoręcznie, wybierz Nie. Pasek nawigacyjny nie będzie wówczas wyświetlany. Styl obramowania Formularze w Accessie, w zależności od ich przeznaczenia, mogą być wyświetlane w różnych rodzajach obramowań: ? Zmienny – umożliwia użytkownikom zmianę rozmiaru formularza. Na oknie umieszczone są przyciski Minimalizuj i Maksymalizuj. ? Dialog – powoduje określenie stałego rozmiaru formularza. Przyciski Minimalizuj i Maksymalizuj są wyłączone. Ustawienie to doskonale nadaje się do okien komunikatu i rozwijanych formularzy. ? Cienki – powoduje określenie stałego rozmiaru formularza. Przyciski Minimalizuj i Maksymalizuj są włączone. ? Brak – brak jakiegokolwiek obramowania. Ustawienie to sprawdza się w przypadku ekranów tytułowych. Pole menu sterowania Właściwość ta określa, czy wyświetlane są przyciski Minimalizuj, Maksymalizuj i Zamknij. Przyciski Min Max Gdy ustawisz tę właściwość na Tak, użytkownicy będą mogli minimalizować i maksymalizować formularze na pulpicie. Przycisk Zamknij Gdy ustawisz tę właściwość na Tak, użytkownicy będą mogli używać menu kontrolnego do zamykania formularza. Jeśli ustawisz tę właściwość na Nie, musisz umożliwić użytkownikom zamknięcie formularza w inny sposób. W innym razie, będą go mogli zamknąć jedynie poprzez kombinacje klawiszy Ctrl+F4 bądź Alt+F4 albo przez zamknięcie Accessa. Zakładka Inne Właściwości znajdujące się w tej kategorii są równie ważne jak te opisane powyżej. Opisują kilka bardzo ważnych aspektów zachowania się formularza i pełnią rolę zestawu zaawansowanych właściwości, służących do wykańczania formularza. Nowością w tej wersji Accessa jest opisana poniżej właściwość Zezwolenie na zmiany projektu. Modalny Gdy właściwość ta ustawiona jest na Tak, po otwarciu formularza żaden inny formularz nie będzie dostępny przed zamknięciem formularza modalnego. Opcja ta sprawdza się jako komunikat o błędzie lub nakaz wykonania przez użytkownika określonych czynności przed przejściem dalej. Podręczny Formularze podręczne są formularzami podrzędnymi w stosunku do okna Accessa. Odróżnia to je od pozostałych formularzy, które są podrzędne w stosunku do formularza, w którym zostały otwarte. Oznacza to, że formularze podręczne mogą być umieszczone w dowolnym miejscu na pulpicie Accessa. Pasek menu, pasek narzędzi Jeśli stworzyłeś własne menu lub paski narzędzi, które chcesz połączyć z określonym formularzem, ustawienie tej właściwości spowoduje, że to menu lub pasek zostaną wyświetlone po uruchomieniu formularza. Menu podręczne Gdy ustawisz tę właściwość na Tak, za każdym razem, gdy użytkownik użyje na formularzu prawego klawisza myszy, zostanie wyświetlone menu, które wybrałeś we właściwości Pasek menu podręcznego. Pasek menu podręcznego Jeśli stworzyłeś dla formularza menu podręczne, wybranie go w tym miejscu i ustawienie właściwości Menu podręczne na Tak nakaże Accessowi wyświetlenie tego menu za każdym razem, gdy użytkownik użyje na formularzu prawego klawisza myszy. Metka Właściwość ta może przechowywać dowolną, wybraną przez Ciebie wartość. Możesz pobrać ją z dowolnego miejsca w aplikacji i zostanie ona zapisana wraz z formularzem. Jeśli formularz oparty jest na kodzie i ustawisz właściwość Ma moduł na Nie, cały kod zostanie usunięty. Access powiadomi Cię o tym fakcie. Ma moduł Po ustawieniu tej właściwości na Nie Access usunie cały kod, na którym oparty jest formularz. W ten sposób „odchudzony” formularz bardzo szybko się ładuje. Jeśli formularz nie zawiera kodu, koniecznie ustaw tę właściwość na Tak. W ten sposób Access nie będzie próbował kompilować formularza za każdym jego ładowaniem. Nie pisząc kodu, możesz dodatkowo poprawić funkcjonalność formularza, wstawiając do niego hiperłącze (opisane w dalszej części tego rozdziału) i łącząc go z obiektem w bazie danych (rysunek 8.2). Rysunek 8.2. Okno dialogowe Wstaw hiperłącze Zezwolenie na zmiany projektu Ustawienie tej właściwości na Wszystkie widoki pozostawia po uruchomieniu formularza otwarte okno dialogowe Format, co umożliwia dokonywanie zmian i oglądanie ich „na żywo” w aplikacji. Nie zapomnij ustawić tej właściwości na Tylko widok projektu po dokonaniu zmian. Użyteczne właściwości nie znajdujące się na arkuszu właściwości Jak zawsze, rzeczy ukryte są dla nas bardziej interesujące niż te ogólnodostępne. Zasada ta ma zastosowanie do ukrytych właściwości formularza. W tym przypadku ukryte właściwości ułatwiają tworzenie w Accessie wykorzystujących formularze, złożonych aplikacji. Argumenty otwarcia (OpenArgs) Właściwość ta jest dostępna jedynie wtedy, gdy formularz działa. Dzięki niej po wprowadzeniu ciągu wartości w jednym formularzu zostanie on automatycznie wprowadzony do drugiego formularza. 'Składnia dla formularza wysyłającego: Docmd.OpenForm "MyForm", "jakiś ciąg wartości" 'Składnia dla formularza odbierającego: Dim x as string If not isnull (OpenArgs) then X = Me.OpenArgs 'wykonaj specjalne formatowanie end if Właściwość ArgumentyOtwarcia przydaje się, gdy do zbierania żądanych informacji używasz formularzy modalnych. Jeśli chcesz sformatować formularz w inny, zgodny z logiką aplikacji sposób, możesz użyć ArgumentyOtwarcia do wysłania „wiadomości” do formularza i pobrania jej podczas zdarzenia Form_Open. W trakcie trwania zdarzenia możesz zmienić wygląd formularza lub zablokować możliwość poruszania się między rekordami, by skoncentrować się na tym rekordzie, który musisz edytować. Po otwarciu formularza jako okna dialogowego nie będziesz mógł go programowo modyfikować, więc jedynym sposobem na zapewnienie zgodności z logiką aplikacji będzie użycie właściwości ArgumentyOtwarcia. Właściwości użytkownika W sekcji ogólnych deklaracji formularza zadeklarowanie zmiennej jako jawnej lub niejawnej spowoduje utworzenie właściwości użytkownika. Aby właściwość ta była dostępna również dla innych modułów, musisz zadeklarować zmienną właściwości jako jawną. Jeśli istnieje potrzeba udostępnienia tej właściwości innym formularzom lub jeśli będziesz chciał dodać walidację przy pobieraniu bądź ustawianiu tej właściwości, możesz do walidacji wykorzystać metody Property Get i Property Let. Załóżmy, że tworzysz aplikację przetwarzającą prawa jazdy i jednym z wymagań jest to, że wiek kierowcy musi być większy niż 16 lat. Do rozwiązania problemu odczytu i zapisu tej właściwości mógłbyś napisać poniższą regułę poprawności. W deklaracjach ogólnych: ' Utwórz w pamięci zmienną intMyAge. Dim intMyAge as Integer ' Użyj tego kodu, by odczytać wartość wejściową i sprawdzić, czy ' odpowiada założonym kryteriom Public Property Let MyAge(byval intAge as Integer) If intAge < 16 then Msgbox "Wiek kierowcy nie może być mniejszy niż 16 lat" Else IntMyAge=intAge End if End Property Użyj tego kodu, aby dodać metodę Property Get. Dzięki temu kod będzie dostępny na zewnątrz formularza. Public Property Get MyAge() as Integer MyAge = intMyAge End Property Gdy chcesz zobaczyć utworzoną właściwość w oknie rozwijanej listy IntelliSense (tak jak ją kodujesz), musisz zadeklarować zmienną formularza typu Form_nazwa_twojego_formularza. Zdarzenia Access posiada ponad 30 zdarzeń, które pomagają kontrolować działanie programu. Bardzo ważnym jest, byś wiedział, w jakiej kolejności zdarzenia te następują. Poniżej znajdziesz informacje na temat kolejności występowania zdarzeń w różnych okolicznościach. Niektóre z tych zdarzeń pomijają parametr Cancel (Anuluj), który może być ustawiony na True, jeśli chcesz zatrzymać otwieranie lub zamykanie formularza. Gdy ustawisz parametr Cancel na True, Access po zatrzymaniu zdarzenia kontynuuje działanie, wyświetlając komunikat o błędzie 2501. Musisz naprawić ten błąd, w przeciwnym wypadku narażasz się na ryzyko kolejnego błędu Accessa (rysunek 8.3). Rysunek 8.3. Błąd Accessa 2501, wyświetlany po ustawieniu parametru Cancel na True Działanie systemu operacyjnego Windows oparte jest na zdarzeniach. Oznacza to, iż poza wewnętrznym zegarem komputera jedynym źródłem działania jest użytkownik. System operacyjny w przeciągu kilku nanosekund odpowiada na uruchamiane zdarzenia i przekazuje je do aktywnej aplikacji. Na następnej stronie umieściliśmy listę zdarzeń uruchamianych podczas pracy użytkownika z formularzem w Accessie. Otwarcie formularza Podczas otwierania formularza określone zdarzenia uruchamiane są w przedstawionej poniżej kolejności. Po ustawieniu parametru Cancel na True, wykonywanie zdarzeń jest zatrzymywane. 15. Otwórz (z opcją Anuluj). 16. Załaduj. 17. Zmień rozmiar. 18. Aktywuj. 19. Aktualny. 20. Wejście do pierwszego formantu. 21. Uzyskanie fokusu przez pierwszy formant. Jeśli na formularzu nie ma formantów, sam formularz uzyska fokus. Jeśli w formularzu umieszczony jest podformularz, następujące zdarzenia wykonywane są PRZED zdarzeniem otwarcia głównego formularza: 1. Otwórz (z opcją Anuluj). 2. Załaduj. 3. Zmień rozmiar. 4. Aktualny. 5. Wejście do pierwszego formantu. 6. Uzyskanie fokusu przez pierwszy formant. Umożliwia to uzyskanie dostępu do pól podformularza z poziomu zdarzenia Otwórz głównego formularza i w razie potrzeby daje możliwość anulowania. Zamknięcie formularza Podczas zamykania formularza określone zdarzenia uruchamiane są w przedstawionej poniżej kolejności. Po ustawieniu parametru Cancel na True wykonywanie zdarzeń jest zatrzymywane. 7. Wyładuj (z opcją anuluj). 8. Dezaktywuj. 9. Zamknij. Zmiana rozmiaru formularza Gdy zmieniany jest rozmiar formularza, określone zdarzenia uruchamiane są w przedstawionej poniżej kolejności. 10. Zmień rozmiar. 11. Dezaktywuj. Maksymalizowanie formularza Gdy formularz jest maksymalizowany, określone zdarzenia uruchamiane są w przedstawionej poniżej kolejności. 12. Zmień rozmiar. Przywrócenie zminimalizowanego formularza Gdy formularz jest przywracany, określone zdarzenia uruchamiane są w przedstawionej poniżej kolejności. 13. Aktywuj. 14. Zmień rozmiar. Formanty formularza w Accessie Aby pomóc Ci w tworzeniu aplikacji, Access 2000 zawiera wiele wbudowanych formatów. Niektóre z nich, jak na przykład pole tekstowe, nie zmieniły się zbytnio od czasów Accessa 1.0. W niektórych, jak pole listy, zaszły znaczące zmiany. W tej części scharakteryzujemy najciekawsze z formantów Accessa. Formant Lista rozwijana Listy rozwijane zawierają zestaw uprzednio zdefiniowanych wartości, co ułatwia użytkownikom wprowadzanie danych poprzez wybieranie z list żądanych wartości. Większość list rozwijanych bazuje na kwerendach lub wyrażeniach SQL i zwykle zawiera jedną lub dwie kolumny i pole związane. Mimo iż dużej części programistów to wystarcza, istnieją interesujące właściwości list rozwijanych Accessa 2000, które mogą znacznie zwiększyć ich funkcjonalność. Użycie zdarzenia Not In List Zdarzenie Not In List uruchamia się automatycznie, gdy wprowadzana jest wartość, która nie znajduje się na liście. Umożliwia to programiście zbadanie tej wartości i podjęcie decyzji, co z nią zrobić. Przykładowo, przyjmijmy, że utworzyłeś listę rozwijaną z klientami i wprowadzono klienta, którego jeszcze nie było na liście. Korzystając z poniższego kodu, mógłbyś wyłapać ten błąd i zapytać użytkownika, czy chce utworzyć nowego klienta: Dim MyResponse AS Variant Dim Msg As String 'Ta procedura uruchamia się tylko wtedy, gdy wykryty zostanie 'obiekt nie znajdujący się na liście Msg = "Klient "& Newdata &" nie został odnaleziony, _ Czy chcesz dodać do listy klientów?" 'Poinformuj użytkownika o nowej wartości. MyResponse = MsgBox(Msg, vbInformation + vbYesNo, _ "Klient nie został odnaleziony") 'Jeśli tak, dodaj kod, by zająć się nową wartością. If MyResponse = vbYes Then MsgBox "Tu wpisz kod", vbInformation _ + vbOKOnly, "Gotowy do dodawania" Me.cboUser = "" Else 'Jeśli nie, wprowadź kod, aby zapytać użytkownika o poprawną wartość. MsgBox "Wybierz z listy innego _ Klienta", vbInformation + vbOKOnly, "Wybierz _ innego Klienta" End If 'Każ Accessowi kontynuować. Opis stałych procedury zdarzenia 'znajdziesz w internetowym pliku pomocy. Response = acDataErrContinue Tworzenie automatycznie rozwijającej się listy rozwijanej Ile razy chciałeś po prostu przejść do pola listy tak, by rozwinęła się automatycznie bez użycia polecenia SendKeys? W Accessie 97, jedyne co musisz zrobić to wpisać poniższą linijkę kodu do zdarzenia Enter: ActiveControl.DropDown To wszystko! Tworzenie własnych list rozwijanych Zazwyczaj wartości w rozwijanych polach pochodzą z tabeli lub kwerendy. Ale to nie jest jedyna możliwość. Ustawiając właściwość Typ źródła wierszy na Lista pól, możesz wybrać przeglądanie pól w bazowej tabeli lub kwerendzie. Możesz również wybrać w tej właściwości nazwę dowolnej funkcji, która będzie wyświetlać dowolną listę. Nawet, jeśli nie zauważysz od razu korzyści płynących z takiego rozwiązania, przydaje się ono, gdy chcesz dodać do listy specjalną wartość jak na przykład Wszystkie. Opcja ta przyda się również, gdy będziesz chciał wyświetlić przydatną dla księgowych, wyrównaną do prawej listę wartości walutowych. To ostatnie rozwiązanie możliwe jest poprzez umieszczenie spacji po lewej stronie wartości i wyświetlenie za pomocą czcionki o stałej szerokości (np. Courier). Oto fragment kodu, znajdujący się w bazie danych Solutions.mdb, który przedstawia sposób, jak dodać u góry listy rozwijanej wartość specjalną Wszystkie. Function AddAllToList(ctl As Control, lngID As Long, _ lngRow As Long, lngCol As Long, intCode As Integer) As Variant ' Dodaje u góry listy wartość specjalną "Wszystkie" ' Można dodać "Wszystkie" do różnych kolumn listy Static dbs As Database, rst As Recordset Static lngDisplayID As Long Static intDisplayCol As Integer Static strDisplayText As String Dim intSemiColon As Integer On Error GoTo Err_AddAllToList Select Case intCode Case acLBInitialize ' See if function is already in use. If lngDisplayID <> 0 Then MsgBox "AddAllToList Jest już używane przez inny formant !" AddAllToList = False Exit Function End If ' Wyłuskanie kolumny do wyświetlenia i wyświetlenie tekstu z ' własności Tag intDisplayCol = 1. strDisplayText = "(Wszystkie)" If Not IsNull(ctl.Tag) Then intSemiColon = InStr(ctl.Tag, ";") If intSemiColon = 0 Then intDisplayCol = Val(ctl.Tag) Else intDisplayCol = Val(Left(ctl.Tag, intSemiColon - 1)) strDisplayText = Mid(ctl.Tag, intSemiColon + 1) End If End If ' Otwórz recordset zdefiniowany przez własność RowSource Set dbs = CurrentDb Set rst = dbs.OpenRecordset(ctl.RowSource, dbOpenSnapshot) ' Zapamiętaj i zwróć lngId lngDisplayID = Timer AddAllToList = lngDisplayID Case acLBOpen AddAllToList = lngDisplayID Case acLBGetRowCount ' Zwróć ilość wierszy w wyniku On Error Resume Next rst.MoveLast AddAllToList = rst.RecordCount + 1. Case acLBGetColumnCount ' Zwróć ilość kolumn w wyniku AddAllToList = rst.Fields.Count Case acLBGetColumnWidth AddAllToList = -1. Case acLBGetValue If lngRow = 0 Then If lngCol = int0isplayCol - 1 Then AddAllToList = strDisplayText Else AddAllToList = Null End If Else rst.MoveFirst rst.Move lngRow - 1 AddAllToList = rst(lngCol) End If Case acLBEnd lngDisplayID = 0 rst.Close End Select Bye_AddAllToList: Exit Function Err_AddAllToList: MsgBox Err.Description, vbOKOnly + vbCritical, "AddAllToList" AddAllToList = False Resume Bye_AddAllToList End Function Pobieranie więcej niż jednej wartości z pola listy i listy rozwijanej Korzystając z właściwości Column, możesz pobrać wartość z dowolnej kolumny w polu listy lub listy rozwijanej. W właściwości Column pierwsza kolumna ma numer 0, druga 1, i tak dalej. Przykładowo, aby odczytać wartość z czwartej kolumny listy rozwijanej, wpisałbyś: MyVariantValue = Me!MyComboBox.Column(3) Pole listy Pole listy przypomina opisaną powyżej listę rozwijaną. Różnica tkwi w możliwości przeglądania wszystkich możliwych wartości bez konieczności rozwijania listy. Również w przeciwieństwie do listy rozwijanej, pole listy umożliwia wybranie kilku wartości jednocześnie. Opcja ta przydaje się w sytuacji, gdy chcesz umożliwić użytkownikowi w tworzonym przez Ciebie systemie przeglądanie informacji o 5 ze 100 wpisów (faktury, ludzie, płyty CD czy ciężarówki). Ponieważ większość właściwości pola listy została już opisana, skoncentrujemy się na różnicach. Pole listy wielokrotnego wyboru W Accessie 2 istniały sztuczki pozwalające na umożliwienie użytkownikom wybieranie kilku wartości z listy. Począwszy od Accessa 2000, wybieranie kilku wartości naraz stało się łatwe dzięki polu listy wielokrotnego wyboru. Jednakże pobieranie wybranych wartości nie zawsze jest tak intuicyjne. Ustawienia właściwości Aby używać pola listy wielokrotnego wyboru, musisz najpierw utworzyć zwykłe pole listy i później przekształcić je w pole wielokrotnego wyboru. Możesz tego dokonać, zmieniając znajdującą się na arkuszu właściwości obiektu właściwość Wybór wielokrotny. W tabeli 8.1 znajdują się możliwe ustawienia. Tabela 8.1. Ustawienia właściwości Wybór wielokrotny Wartość Znaczenie Brak Wybór wielokrotny nie jest możliwy. Prosty Elementy wielokrotne wybierane są przez kliknięcie myszką lub naciśnięcie klawisza spacji. Rozszerzony Elementy wielokrotne wybierane są przez przytrzymanie klawisza Shift i kliknięcie ich myszką lub przez przytrzymanie klawisza Shift i naciśnięcie klawisza strzałki (powoduje to rozszerzenie zaznaczenia od poprzednio wybranego do aktualnego elementu). Możesz również zaznaczać elementy, przeciągając je myszką. Przytrzymanie klawisza Ctrl i klinięcie go myszką powoduje jego zaznaczenie lub zniesienie zaznaczenia. Aby pobrać wartości, będziesz musiał posłużyć się kodem. Przykładowo, by odczytać wartości z listy pracowników, mógłbyś napisać następujący fragment kodu: Dim strMsg As String Dim strName As String Dim i As Integer 'Utwórz ciąg przechowujący wiadomość. strMsg = "Wybrano następujących pracowników: " _ & vbCr & vbCr For i = 1 To Me.lstMulti.ListCount 'Sprawdź, czy użytkownik zaznaczył ten wiersz. If Me.lstMulti.Selected(i) Then 'Jeśli tak, dodaj pierwszą kolumnę zaznaczonego wiersza ' do ciągu wiadomości. StrName = Me.lstMulti.Column(0, i) 'Pobierz wartość obiektu (pola związanego) i dodaj ją 'do ciągu. Spowoduje to utworzenie wyświetlanego 'imienia i nazwiska. StrName = strName & Chr(32) & _ Me.lstMulti.ItemData(i) strMsg = strMsg & strName & vbCr End If Next MsgBox Msg Kod ten nie tylko odczytuje wartości z pola listy, ale również wykorzystuje właściwość column w celu pobrania wartości z więcej niż tylko jednej, związanej kolumny. Podformularze Podformularze zawsze były świetnym sposobem na prezentowanie danych w relacji jeden-do-wielu. Korzystając z nadrzędnego i podrzędnego pola łączącego, programiści mogą z łatwością powiązać ze sobą dane w relacji. Podformularze posiadają jeszcze jedną bardzo przydatną cechę. Zmieniając właściwość Obiekt źródłowy, programiści mogą wstawiać do jednego, głównego formularza nieograniczoną ilość podformularzy. Dzięki temu, programiści mogą tworzyć własne zbiory obiektów, czyli coś, czego nie można było zrobić w Visual Basicu. Zbiory te umożliwiają grupowanie obiektów i odnoszenie się do nich jako całości. Dodatkowo, podformularze są doskonałym sposobem na obejście dwudziesto-dwu calowego limitu długości formularzy w Accessie. Podformularze umożliwiają również szybsze ładowanie formularzy, gdyż nie muszą ładować każdego formularza, pola listy czy pola memo, którego mógłby potrzebować użytkownik. Programiści mogą kontrolować sposób przedstawiania danych i ograniczać ilość elementów graficznych lub innych zasobochłonnych obiektów. Dodawanie podformularzy Istnieją trzy sposoby dodawania do formularza podformularzy: ? Po otwarciu formularza w widoku Projekt wybierz z przybornika obiekt Podformularz i przeciągnij go na główny formularz. Utworzony zostanie pusty podformularz. Następnie dodaj obiekt źródłowy oraz nadrzędne i podrzędne pole łączące. ? Drugi sposób jest jeszcze prostszy. Otwórz główny formularz w widoku Projekt i przejdź do okna bazy danych. Przeciągnij formularz, którego chcesz użyć jako podformularza z okna bazy danych na główny formularz. Access spróbuje połączyć nadrzędne i podrzędne pola i ustawić za Ciebie obiekt źródłowy. Access ustawi również rozmiar podformularza tak, by dobrze pasował do okna głównego formularza. Ręczne wykonywanie tej czynności może czasami przysporzyć wielu trudności. ? Użyj dołączonego do Accessa kreatora podformularzy. W Accessie 97 Kreator formantów był domyślnie włączony. W Accessie 2000 jest inaczej. Aby użyć tego kreatora, upewnij się, czy znajdujący się w Przyborniku przycisk Kreatorzy formantów jest wciśnięty (rysunek 8.4). Gdy tworzysz nowy podformularz w widoku Projekt formularza, Kreator podformularzy zostanie uruchomiony automatycznie. Tworzenie odniesienia dla podformularza Istnieje kilka sposobów tworzenia odniesień dla formantów na podformularzu. Typowa składnia wygląda następująco: Forms!MyForm!SubFormControlName.Form!ControlName Metoda ta uległa znacznemu poprawieniu w Accessie 2000, ponieważ zbiór formantów jest domyślnym zbiorem dla formularza. Teraz możesz stworzyć odniesienie dla tego samego obiektu w następujący sposób: Forms!MyForm!SubFormControlName!ControlName lub Me!MyForm!SubFormControlName!ControlName W obu przypadkach efekt będzie ten sam. Aby mieć pewność co do składni, skorzystaj z kreatora wyrażeń (Ctrl+F2). Rysunek. 8.4. Przybornik z wciśniętym przyciskiem Kreatora formantów Wbudowany formant Karta Innym sposobem na łączenie formantów jest zastosowanie formantu Karta. Jest on jednym z wbudowanych obiektów Accessa 2000. Grupa opcji Programiści Visual Basica mieli do swojej dyspozycji tablice obiektów (czyli możliwość tworzenia odniesień do grupy formantów za pomocą tej samej nazwy, lecz innego indeksu). Dzięki temu możliwe było znaczne uproszczenie procesu ustawiania właściwości lub zmiany wartości. Niestety, poza formantem Grupa opcji, w Accessie 2000 nie ma takiej możliwości. Dzięki temu formantowi, możesz wewnątrz ramki umieścić pola wyboru, przyciski opcji lub przyciski przełącznika, a następnie tworzyć odniesienia do każdego obiektu według wartości jego indeksu. Możesz jednym poleceniem (zamiast pięciu czy sześciu) włączać lub wyłączać właściwość Widoczny obiektów wewnątrz ramki. Możesz także używać konstrukcji For Each, aby przejść przez wszystkie wartości wewnątrz grupy opcji, zamiast testować każdą z nich osobno. Podręczne menu Podręczne menu pojawiły się wraz z systemem Windows 95. Większość z tych użytkowników, którzy z Windows 95 powrócili do Windows 3x, przeklina niemożność korzystania z prawego przycisku myszy. Podręczne menu to doskonały sposób na skrócenie wykonywania najpopularniejszych czynności lub umożliwienie korzystania z charakterystycznych dla danego obiektu opcji. Formularze, a nawet pojedyncze formanty, mogą posiadać swoje własne menu podręczne, a odrobina kodu pomoże Ci na bieżąco modyfikować wygląd pasków poleceń. Aby utworzyć podręczne menu, kliknij dowolny pasek narzędzi lub pasek menu i wybierz Dostosuj. Możesz również wybrać z menu Widok pozycję Paski narzędzi==>Dostosuj. 15. Na zakładce Paski narzędzi kliknij Nowy... 16. W polu Nazwa paska narzędzi wpisz dowolną nazwę i kliknij OK. 17. Na zakładce Paski narzędzi kliknij Właściwości. 18. Z listy Typ wybierz Podręczny. 19. Ustaw właściwość Zezwalaj na dostosowanie w żądany sposób i kliknij Zamknij. Nie martw się, nie stracisz tego paska. 20. W oknie Paski narzędzi kliknij Menu podręczne. 21. Na pasku narzędzi Menu podręczne kliknij kategorię Niestandardowe. Tam znajdziesz swoje nowe menu podręczne. 22. Aby wykończyć menu, postępuj w następujący sposób: Dodaj polecenia z okna dialogowego Dostosuj. Przenoś lub kopiuj polecenia z innych menu. Hiperłącza Hiperłącza to niezmiernie przydatne formanty, umożliwiające użytkownikowi przechodzenie za jednym kliknięciem do formularzy, raportów, arkuszy Excela, dokumentów Worda czy nawet stron WWW. Ponieważ nie kryją one za sobą kodu, idealnie nadają się do formularzy nawigacyjnych. Można ich używać na „odchudzonych” formularzach (tych z właściwością Ma moduł ustawioną na Nie). Hiperłącze jest niepołączoną etykietą (etykieta bez obiektu nadrzędnego) z właściwościami Adres hiperłącza i Podadres hiperłącza ustawionymi na Null. Rozdział 9. Rozbudowa formularzy przy użyciu formantów ActiveX W tym rozdziale: ? Jak korzystać z formantów ActiveX. ? Użycie formantów ActiveX. ? 21 formantów ActiveX. ? Rozpowszechnianie formantów ActiveX. Formanty ActiveX umożliwiają zwiększenie zestawu funkcji aplikacji pisanych w Accessie, ułatwiając ich tworzenie i obsługę. Możliwości, jakie dają programistom, są nieograniczone. Z tego rozdziału dowiesz się, jakie formanty ActiveX masz do swojej dyspozycji i nauczysz się dodawać je do formularzy Accessa. Najpierw jednak powiemy, czym są i skąd wzięły się formanty ActiveX. Jak korzystać z formantów ActiveX Miałeś już okazję zapoznać się z wbudowanymi formantami, które można umieszczać na formularzach Accessa (np. pola tekstowe czy przyciski poleceń). Formanty ActiveX działają w bardzo podobny sposób, z tą różnicą, że kod obsługujący zestaw funkcji formantu ActiveX przechowywany jest w osobnym pliku, który przed użyciem musi zostać zainstalowany. Formanty ActiveX pozwalają na wzbogacenie tworzonych aplikacji o funkcje, których nie udostępniał Access. Mógłby to być, na przykład, kalendarz lub formant siatki. Formanty ActiveX są zazwyczaj przechowywane w folderze systemowym i są plikami o rozszerzeniu OCX lub DLL. Formanty ActiveX nie są częścią Accessa, jednakże mogą być używane w jego aplikacjach. Działają dokładnie w ten sam sposób, co pozwala na uzyskanie wysokiej wydajności. W tym rozdziale pokażemy, jak używać formantów ActiveX w formularzach Accessa, jednakże te same formanty mogą być użyte w aplikacjach Visual Basic, Office, a nawet w aplikacjach działających w sieci WWW. Nie każdy formant ActiveX będzie działał we wszystkich aplikacjach. Formant świetnie działający w Visual Basicu może nie działać w Accessie i na odwrót. Aby się przekonać, czy dany formant ActiveX będzie działał w Accessie, przejrzyj jego dokumentację lub sam przeprowadź odpowiednie testy. Typy formantów ActiveX Istnieją dwa typy formantów ActiveX: formanty związane z procesem projektowania i formanty wykorzystywane podczas użytkowania aplikacji. Formanty związane z procesem projektowania umieszczane są na formularzach Accessa, lecz nie są nigdy widoczne dla ostatecznego użytkownika. Formanty te zawierają kod, który powiększa zestaw funkcji dostępnych dla programisty. Widoczne są one w procesie projektowania, a nie podczas używania aplikacji, tak więc ostateczny użytkownik ich nie widzi. Przykładem formantów związanych z procesem projektowania są formanty Image oraz Common Dialog. Formanty wykorzystywane podczas użytkowania aplikacji zawierają interfejs użytkownika, który jest dla ostatecznego użytkownika widoczny. Omówione w dalszej części tego rozdziału przykłady tego typu formantów to: Toolbar, MonthView, ListView, a także wiele innych. Formanty tego typu widoczne są zarówno podczas fazy projektowania, jak i podczas użytkowania aplikacji. W tej drugiej fazie użytkownicy mają możliwość manipulowania formantami w określony sposób. Gdzie znaleźć formanty ActiveX? Bez wątpliwości wiele formantów ActiveX znajduje się już na Twoim komputerze. Być może nawet nie uda Ci się ustalić pochodzenia części z nich. Oto kilka możliwych źródeł: ? Windows. ? Aplikacje Microsoft Office. ? Visual Basic. ? Internet Explorer. ? Inne aplikacje. ? Inni producenci. ? Pliki pobrane ze stron sieci WWW. ? Formanty ActiveX, które utworzyłeś za pomocą C++, Java czy Visual Basica. Więcej informacji o tworzeniu własnych formantów ActiveX znajdziesz w rozdziale 20., „Użycie Visual Basic z Accessem”. Doradzamy testowanie formantów ActiveX przed ich użyciem. Wiele formantów można znaleźć w Internecie. Sprawdź, czy dany formant odpowiada Twoim potrzebom, zanim go zakupisz. Czy formanty ActiveX są bezpieczne? Niekoniecznie. Formanty ActiveX zawierają kod. Złośliwy programista mógłby bez trudu utworzyć formant, który dokona poważnych uszkodzeń systemu operacyjnego Twojego komputera. Doradzamy korzystanie jedynie z formantów pochodzących ze sprawdzonych źródeł. Czy mogę korzystać z formantów ActiveX i rozpowszechniać je w moich aplikacjach? To, że dany formant znajduje się na Twoim komputerze, nie oznacza wcale, że możesz z niego korzystać i umieszczać go w swoich aplikacjach. Powinieneś zadać sobie pytanie: „Czy mam prawo korzystać z danego formantu ActiveX?” Ważnym jest, by dokładnie przeczytać dotyczącą formantu umowę licencyjną. Przykładowo, mogłeś otrzymać formanty dokonując zakupu narzędzi programistycznych od firmy Microsoft. Przeczytaj umowę licencyjną, aby sprawdzić, czy możesz korzystać z tych formantów i rozpowszechniać je bez dodatkowych opłat. Powinieneś postępować w ten sam sposób, kupując formanty od innych firm. Formanty, których nie kupowałeś, mogą pochodzić z Internetu. Najprawdopodobniej nie będziesz miał prawa do umieszczania ich w swoich aplikacjach. Często, gdy próbujesz użyć formantu ActiveX w swojej aplikacji, wyświetlane jest ostrzeżenie, że nie masz praw do używania i rozpowszechniania tego formantu. Przestrzeganie umów licencyjnych jest zapewnione z mocy prawa. Niewłaściwe użycie bądź bezprawne rozpowszechnianie formantu ActiveX jest tym samym co nielegalne kopiowanie oprogramowania. Może być ścigane jak przestępstwo kryminalne albo pociągnąć za sobą roszczenia odszkodowawcze ze strony poszkodowanego. Użycie formantów ActiveX Użycie formantów ActiveX w Accessie wymaga wykonania następujących kroków: 23. Zainstalowania formantu na komputerze. 24. Zarejestrowania formantu. 25. Dodania formantu do formularza. 26. Ustawienia właściwości formantu. 27. Dodania kodu, który umożliwi wykonanie metod i reagowanie na zdarzenia. Instalowanie formantu ActiveX Formant ActiveX musi zostać zainstalowany na komputerze, w innym bowiem przypadku, gdy aplikacja będzie chciała go użyć, wyświetlony zostanie komunikat o błędzie. Oznacza to, że za każdym razem, gdy rozpowszechniasz aplikację, musisz upewnić się, że dołączyłeś do niej również wymagane formanty ActiveX. O tym jednak w dalszej części tego rozdziału. Jeśli rozpowszechniasz aplikację korzystającą z formantów ActiveX, powinieneś się upewnić, czy wymagane formanty są zainstalowane na każdym z komputerów, na których aplikacja będzie uruchamiana. I tak, przykładowe aplikacje dla tego rozdziału nie będą działać na Twoim komputerze, jeśli nie zainstalujesz odpowiednich formantów ActiveX. Rejestrowanie formantów ActiveX Zanim formant ActiveX zostanie dodany do formularza Accessa, musi zostać zarejestrowany. Aby określić, czy formant został zarejestrowany, spróbuj dołączyć go do formularza (opis tej czynności znajdziesz w następnym rozdziale). Jeśli Ci się to uda, znaczy to, że formant został już zarejestrowany. W przeciwnym wypadku musisz zarejestrować go przy użyciu Accessa. Niektóre formanty ActiveX rejestrowane są automatycznie po ich zainstalowaniu. Aby zrobić to ręcznie, gdy formularz otwarty jest w widoku Projekt, z menu Narzędzia wybierz pozycję Formanty ActiveX. Wyświetlone zostanie okno dialogowe Formanty ActiveX. Wybierz formant, który chcesz zarejestrować i kliknij przycisk Zarejestruj. Wyświetlone zostanie okno dialogowe Dodaj formant ActiveX. Wybierz odpowiadający wybranemu formantowi plik (.OCX) i kliknij OK. (rysunek 9.1). Rysunek 9.1. Okno dialogowe Dodaj formant ActiveX Dodawanie formantu ActiveX do formularza Jeśli formant ActiveX jest już zarejestrowany, możesz dodać go do formularza. Aby tego dokonać, otwórz formularz w widoku Projekt i z menu Wstaw wybierz Formant ActiveX lub kliknij znajdujący się w prawym dolnym rogu Przybornika przycisk Więcej formantów (rysunek 9.2). Rysunek 9.2. Znajdujący się w Przyborniku przycisk Więcej formantów przycisk Więcej formantów Wyświetlone zostanie okno dialogowe Wstawianie formantu ActiveX. Wybierz formant, który chcesz dodać do formularza, i kliknij przycisk OK. (rysunek 9.3). Okno dialogowe zostanie zamknięte. Na formularzu kliknij miejsce, w którym chcesz umieścić formant. Rysunek 9.3. Wybierz formant ActiveX, który chcesz dodać do formularza Po wstawieniu formantu Access zachowuje odniesienie do właściwej dla niego biblioteki. Aby wyświetlić wszystkie odniesienia w aplikacji, otwórz edytor Visual Basic i z menu Tools wybierz pozycję References (rysunek 9.4). Rysunek 9.4. Formanty ActiveX wyświetlone w oknie dialogowym References Ustawianie właściwości formantu ActiveX Formanty ActiveX posiadają arkusz właściwości identyczny jak wbudowane formanty Accessa. Mają również stronę z właściwościami przypominającą arkusz właściwości formularza, co znacznie ułatwia ustawianie właściwości. Aby otworzyć stronę z właściwościami formantu ActiveX, kliknij go prawym klawiszem myszy i z menu kontekstowego wybierz pozycję Obiekt, a następnie Properties (rysunek 9.5). Rysunek 9.5. Strona z właściwościami formantu ImageList Pisanie kodu umożliwiającego wykonywanie metod i reagowanie na zdarzenia W przypadku formantów ActiveX pisanie kodu umożliwiającego wykonywanie metod i reagowanie na zdarzenia nie różni się niczym od pisania kodu dla wbudowanych formantów Accessa. Aby uzyskać informacje o właściwościach, metodach i zdarzeniach związanych z formantem, skorzystaj z narzędzia Object Browser (rysunek 9.6). Rysunek 9.6. Korzystaj z narzędzia Object Browser, by uzyskać informacje o właściwościach, metodach i zdarzeniach związanych z formantem 21 formantów ActiveX Teraz omówimy 21 formantów ActiveX. Można by oczywiście wiele napisać o wszystkich formantach ActiveX (których są setki), ale niektóre z nich dostarczane są przez firmę Microsoft. W znajdującej się na dołączonym do książki CD-ROM-ie aplikacji znajdziesz przykłady kodu użyte we wszystkich z 21 formantów ActiveX. Tabela 9.1 zawiera nazwę formantu, nazwę jego pliku i opis. Tabela 9.1. Przegląd formantów ActiveX Formant ActiveX Nazwa pliku Opis Animation MSCOMCT2.OCX Odtwarza w formularzu pliki video (AVI) Calendar Wyświetla w formularzu kalendarz Common Dialog COMDLG32.OCX Wyświetla okna dialogowe Otwórz, Zapisz jako, Kolor, Czcionka, Drukuj i Pomoc DateTimePicker MSCOMCT2.OCX Rozwijany kalendarz, który umożliwia użytkownikom wprowadzanie dat FlatScrollBar MSCOMCT2.OCX Płaski pasek przewijania Tabela 9.1. Przegląd formantów ActiveX (ciąg dalszy) Formant ActiveX Nazwa pliku Opis ImageCombo MSCOMCTL.OCX Pole kombi zawierające rysunki związane z obiektami na liście ImageList MSCOMCTL.OCX Zawiera bitmapy i obrazki, które mogą być używane przez inne formanty ListView MSCOMCTL.OCX Przedstawia dane na liście na cztery różne sposoby MAPIMessages MSMAPI32.OCX Wysyła i odbiera wiadomości, wyświetla książki adresowe i inne opcje związane z pocztą MAPISession MSMAPI32.OCX Umożliwia rozpoczęcie i zamknięcie sesji MAPI MonthViev MSCOMCT2.OCX Interfejs w formie kalendarza, umożliwiający przeglądanie i wybieranie informacji o datach ProgressBar MSCOMCTL.OCX Wyświetla informacje o stanie zaawansowania danego procesu RichText RICHTX32.OCX Umożliwia formatowanie tekstu w polach tekstowych (zmianę rodzaju czcionki, jej koloru, rozmiaru i inne) Slider MSCOMCTL.OCX Poziomy i pionowy suwak StatusBar MSCOMCTL.OCX Umieszcza na formularzu pasek stanu SysInfo SYSINFO.OCX Odbiera i wysyła informacje o systemie TabStrip MSCOMCTL.OCX Rozmieszcza zakładki w rzędach i wyświetla na nich rysunki ToolBar MSCOMCTL.OCX Umieszcza na formularzu pasek narzędzi TreeView MSCOMCTL.OCX Wyświetla dane w formacie hierarchicznym UpDown MSCOMTC2.OCX Umożliwia użytkownikom zwiększanie i zmniejszanie wartości innego formantu WebBrowser SHDOCVW.DLL Wyświetla na formularzu przeglądarkę WWW Znajdujący się na płycie CD-ROM kod dla tego rozdziału zawiera przykłady każdego z tych formantów. Formant Animation Formant ten umożliwia odtwarzanie na formularzu Accessa plików wideo (.AVI) (rysunek 9.7). Tabela 9.2 zawiera najczęściej używane właściwości i metody dla formantu Animation. Rysunek 9.7. Przykład formantu Animation Formant Animation nie obsługuje wszystkich plików typu AVI. Przykładowo, formant ten nie współpracuje z plikami AVI zawierającymi dźwięk. Ponadto plik AVI nie powinien być kompresowany. Jedynym wyjątkiem są pliki kompresowane przy użyciu kompresji Run-Length. Tabela 9.2. Właściwości i metody dla formantu Animation Obiekt Opis Właściwość AutoPlay Jeśli właściwość ta jest ustawiona na True, plik AVI odtwarzany jest w pętli od momentu jego załadowania do formantu. Przy ustawieniu False plik nie jest odtwarzany aż do wywołania metody Play Metoda Close Zamyka otwarty plik AVI Metoda Open Otwiera plik AVI Metoda Play Odtwarza załadowany do formantu plik AVI Metoda Stop Zatrzymuje rozpoczęte za pomocą metody Play odtwarzanie pliku AVI Formant Calendar Formant Calendar wyświetla w formularzu Accessa kalendarz (rysunek 9.8). Formant Calendar przydaje się do ustawiania i pobierania wartości daty. W zależności od ustawienia, może on zawierać dzień, miesiąc i rok. Tabela 9.3 zawiera najczęściej używane właściwości, metody i zdarzenia dla formantu Calendar. Formant Common Dialog Dzięki użyciu formantu Common Dialog można z łatwością wyświetlać typowe okna dialogowe systemu Windows – Otwórz, Zapisz jako, Kolor, Czcionka, Drukuj i Pomoc (rysunek 9.9). Rysunek 9.8. Przykład formantu Calendar Tabela 9.3. Właściwości, metody i zdarzenia dla formantu Calendar Obiekt Opis Właściwość Day Ustawia dzień miesiąca (1–31) Właściwość Month Ustawia miesiąc Właściwość ShowDateSelectors Wyświetla rozwijane pole listy selektora daty Właściwość Value Ustawia lub pobiera wybraną datę Właściwość Year Ustawia rok Metoda NextDay Wyświetla następny dzień Metoda PreviousDay Wyświetla poprzedni dzień Metoda Today Wyświetla dzisiejszą datę Zdarzenie Click Występuje, gdy użytkownik kliknie datę Rysunek 9.9. Przykład formantu Common Dialog Formant ten związany jest z procesem projektowania. Wystarczy wstawić formant do formularza i przywołać metodę wyświetlającą żądane okno dialogowe. Poniższy kod powoduje wyświetlenie okna dialogowego Kolor: Me.ActiveXCommonDialogControl.ShowColor Tabela 9.4 zawiera najczęściej używane właściwości i metody dla formantu Common Dialog. Tabela 9.4. Właściwości i metody dla formantu Common Dialog Obiekt Opis Właściwość Color Pobiera kolor wybrany w oknach dialogowych Kolor i Czcionka Właściwość Copies Ilość kopii do wydrukowania z okna dialogowego Drukuj Właściwość Filter Określa typ lub nazwę pliku dla okien dialogowych Otwórz i Zapisz jako Właściwość FontName Czcionka wybrana w oknie dialogowym Czcionka Właściwość FontSize Rozmiar czcionki wybrany w oknie dialogowym Czcionka Właściwość Orientation Orientacja strony (pionowa lub pozioma) z okna dialogowego Drukuj Metoda ShowColor Wyświetla okno dialogowe Kolor Metoda ShowFont Wyświetla okno dialogowe Czcionka Metoda ShowHelp Wyświetla Pomoc Metoda ShowOpen Wyświetla okno dialogowe Otwórz Metoda ShowPrinter Wyświetla okno dialogowe Drukuj Metoda ShowSave Wyświetla okno dialogowe Zapisz jako Formant DateTimePicker Formant DateTimePicker umożliwia wyświetlenie rozwijanego kalendarza, który ułatwia użytkownikom wprowadzanie dat w formularzu (rysunek 9.10). Przypomina on formant daty programu Outlook, używany do planowania zajęć. Rysunek 9.10. Przykład formantu DateTimePicker Powyższy przykład przedstawia rozwijany kalendarz służący do wybierania daty. Użytkownik ma również możliwość zmiany wprowadzonej w tym formancie daty przy użyciu klawiszy strzałek (góra – dół). Przykładowo, gdy wprowadzono datę 7/15/99, gdzie 7 oznacza miesiąc, 15 – dzień, a 99 – rok, za pomocą klawiszy strzałek można te wartości zmodyfikować. Wygląd rozwijanego kalendarza może być zmieniany przy użyciu różnych zestawów kolorów (patrz właściwości w tabeli 9.5). Tabela 9.5 zawiera najczęściej używane właściwości dla formantu DateTimePicker. Tabela 9.5. Właściwości formantu DateTimePicker Obiekt Opis Właściwość CalendarBackColor Ustawia bądź pobiera kolor tła rozwijanego kalendarza Właściwość CalendarForeColor Ustawia bądź pobiera kolor pierwszego planu kalendarza rozwijanego Właściwość CalendarTitleBackColor Ustawia bądź pobiera kolor tła tytułu rozwijanego kalendarza Właściwość CalendarTitleForeColor Ustawia bądź pobiera kolor pierwszego planu tytułu rozwijanego kalendarza Właściwość CalendartrailingForeColor Ustawia bądź pobiera kolor pierwszego planu dat w rozwijanym kalendarzu Właściwość Checkbox Umieszcza w formancie pola wyboru Właściwości Day, Month i Year Zwraca wybraną wartość Właściwość DayOfWeek Zwraca dzień tygodnia Właściwość Format Wyświetla datę długą, datę krótką, czas i inne formanty Właściwości MinDate i MaxDate Określa zakres daty Właściwości Second, Minute i Hour Zwraca wybrane właściwości Właściwość Value Ustawia bądź pobiera wybraną datę/godzinę Formant FlatScrollBar Oto nowa wersja suwaka o płaskim wyglądzie (rysunek 9.11). Poprzez zmianę właściwości Orientation możesz wybrać suwak poziomy lub pionowy. Rysunek 9.11. Przykład formantu FlatScrollBar Tabela 9.6 zawiera najczęściej używane właściwości formantu FlatScrollBar. Tabela 9.6. Właściwości formantu FlatScrollBar Obiekt Opis Właściwość Appearance Ustawia bądź pobiera wygląd suwaka. Suwak może być dwu- lub trójwymiarowy Właściwość Orientation Ustawia bądź pobiera położenie (poziome lub pionowe) suwaka Formant ImageCombo Formant ImageCombo przypomina zwykłe pole listy rozwijalnej, z tą różnicą, że pozycjom na liście można przyporządkować rysunki (rysunek 9.12). To ułatwia użytkownikom korzystanie z listy. Rysunek 9.12. Przykład formantu ImageCombo Do umieszczenia rysunków w formancie ImageCombo używany jest formant ImageList. Rysunek może być umieszczony obok tekstu na liście lub w części edycyjnej pola listy. Aby programowo dodawać obiekty do formantu ImageCombo, użyj metody Add w następujący sposób: With ctlImageCombo.ComboItems ' Add Index, ItemNames, ListBox Display Name, Image Key Name. .Add 1, "Cloudy", "Cloudy", "Cloudy" .Add 2, "Rainy", "Rainy", "Rainy" .Add 3, "Snowing", "Snowing", "Snowing" .Add 4, "Sunny", "Sunny", "Sunny" .Add 5, "Lightning", "Lightning", "Lightning" End With Tabela 9.7 zawiera najczęściej używane właściwości, metody i zdarzenia dla formantu ImageCombo. Tabela 9.7. Właściwości, metody i zdarzenia dla formantu ImageCombo Obiekt Opis Obiekt Collection Zbiór ComboItems (obiektów listy rozwijalnej) Obiekt Individual Obiekt ComboItem jest obiektem na liście Właściwość ComboItems Pobiera odnośnik do zbioru ComboItems Tabela 9.7. Właściwości, metody i zdarzenia dla formantu ImageCombo (ciąg dalszy) Obiekt Opis Właściwość ImageList Przyporządkowuje formant ImageList do ImageCombo Właściwość Indentation Ustawia bądź pobiera szerokość wcięć (każde wcięcie wynosi 10 pikseli) Właściwość SelectedItem Wybrany obiekt z listy Metoda Add Programowe dodawanie obiektów do ImageCombo Zdarzenie DropDown Występuje po rozwinięciu listy formantu Formant ImageList Formant ImageList należy do grupy formantów związanych z procesem projektowania. Jest on niewidoczny dla ostatecznego użytkownika. Formant ten służy do przechowywania plików rysunków. Możesz przechowywać wiele typów rysunków: bitmapy (.BMP), ikony (.ICO), pliki typu .GIF, .DIB, .CUR i .JPG. Z rysunków przechowywanych w formancie ImageList mogą później korzystać inne formanty. W ten sposób działają omówione w tym rozdziale formanty ActiveX ImageCombo, ListView i Toolbar. Dzięki stronie z właściwościami formantu ImageList (rysunek 9.13) dodawanie rysunków jest dość proste. Pamiętaj, że rysunki dodawane do formantu ImageList muszą być tego samego rozmiaru. Jeśli chcesz korzystać z rysunków o różnych rozmiarach, musisz użyć kilku formantów ImageList. Rysunek 9.13. Strona z właściwościami formantu ImageList Rysunkom dodawanym do formantu ImageList zawsze przyznawane są numery indeksu. Nie powinieneś się na nich opierać. Zamiast tego, zawsze wprowadzaj wartość Key (wartość klucza) dla każdego rysunku. Po usunięciu obiektów z formantu ImageList wartości indeksu ulegają zmianie, więc nie możesz się na nich opierać. Zawsze korzystaj z unikatowych wartości klucza i używaj ich przy tworzeniu odniesień do rysunków w kodzie. Nie przesadzaj z użyciem rysunków w aplikacjach. Formant ImageList pochłania dużą część pamięci komputera i użycie większej ilości rysunków może spowodować zmniejszenie wydajności aplikacji. Po otwarciu formularza zawierającego ten formant wszystkie rysunki przechowywane są w pamięci. Tabela 9.8 zawiera najczęściej używane właściwości, metody i zdarzenia dla formantu ImageList. Tabela 9.8. Właściwości, metody i zdarzenia dla formantu ImageList Obiekt Opis Obiekt Collection Zbiór ListImages Obiekt Individual Obiekt ListImage jest rysunkiem w formancie Właściwość Index Unikatowa wartość indeksu dla każdego rysunku Właściwość Key Wartość tekstowa przyporządkowana rysunkowi Właściwość ImageCount Aktualna liczba rysunków w formancie ImageList Metoda Overlay Nadpisywanie jednego rysunku na drugim Add (dodaj) rysunki Używana w kodzie metoda Add dla zbioru ListImages Przykład wykorzystania rysunków w formularzu przy użyciu formantu ImageList przedstawiony jest na rysunku 9.14. Formant ListView może korzystać z rysunków tylko dzięki formantowi ImageList. Po związaniu formantu ImageList z innym formantem nie możesz do niego dodawać nowych rysunków. Przed umieszczeniem formantu na formularzu upewnij się, że dodałeś wszystkie zaplanowane rysunki. Jeśli będziesz chciał dodać rysunki do formantu ImageList po związaniu go z innym formantem, najpierw będziesz musiał je rozłączyć. Formant ListView Formant ListView wyświetla listę obiektów na cztery różne sposoby. Jako przykład może posłużyć prawe okno Eksploratora Windows, w którym użytkownicy mogą przeglądać pliki w formatach Duże ikony, Małe ikony, Lista i Szczegóły. W formularzach Accessa listy z danymi mogą być wyświetlane w podobny sposób dzięki formantowi ListView (rysunek 9.14). Obiekty na liście mogą być umieszczone z nagłówkami kolumn lub bez nich. Formant ten jest bardzo elastyczny i umożliwia przeglądanie danych na wiele różnych sposobów. Rysunek 9.14. Przykład formantu ListView Tabela 9.9 zawiera najczęściej używane obiekty i właściwości formantu ListView. Tabela 9.9. Obiekty i właściwości formantu ListView Obiekt Opis Obiekt Collection Zbiór ListItems Obiekt Individual Obiekt ListItem jest obiektem na liście Obiekt Collection Zbiór ColumnHeaders Obiekt Individual Obiekt ColumnHeader, tekst nagłówka kolumny Właściwość AllowColumnReorder Zmienia układ kolumn Właściwość Arrange Rozmieszcza ikony w formancie Właściwość ColumnHeaders Tworzy odniesienie zbioru do obiektów ColumnHeader Właściwość FullRowSelect Wybór całego wiersza Właściwość GridLines Wyświetla linie siatki w widoku Szczegóły Właściwość HideColumnHeaders Ukrywa i odkrywa nagłówki kolumn w widoku Szczegóły Właściwość LabelEdit Umożliwia użytkownikom edytowanie etykiet Właściwość LabelWrap Zawija etykiety obiektów ListItems Właściwość MultiSelect Umożliwia użytkownikom zaznaczanie kilku obiektów Właściwość SelectedItem Określa wybrany ListItem Tabela 9.9. Obiekty i właściwości formantu ListView (ciąg dalszy) Obiekt Opis Właściwość Sorted Określa, czy obiekty w zbiorze mają być sortowane Właściwość SortKey Określa, czy obiekty mają być sortowane według właściwości ListItem Text, czy według indeksu zbioru SubItems Właściwość SortOrder Sortowanie rosnąco i malejąco Właściwość SubItems Tablica ciągów wyświetlana w widoku Szczegóły Właściwość View Ustawia wygląd obiektów: Duże ikony, Małe ikony, Lista i Szczegóły Użycie formantu ListView w połączeniu z formantem TreeView znacznie zwiększa funkcjonalność interfejsu Eksploratora Windows. Jest to bardzo dobry sposób na przeglądanie danych, gdyż większość użytkowników miała już okazję poznać ten interfejs. Formant MAPISession Interfejs MAPI (ang. Messaging Application Programming Interface) nadzoruje korzystające z poczty aplikacje Accessa. Formant MAPISession umożliwia rozpoczęcie i zamknięcie sesji MAPI (rysunek 9.15). Rysunek 9.15. Przykład formantu MAPISession Aby formanty MAPI funkcjonowały poprawnie, konieczne jest zainstalowanie na komputerze usługi MAPI oraz zgodnego z nią systemu poczty elektronicznej (na przykład Microsoft Exchange). Formant MAPISession związany używany jest w procesie projektowania i nie są z nim związane żadne zdarzenia. Tabela 9.10 zawiera najczęściej używane właściwości i metody dla formantu MAPISession. Tabela 9.10. Właściwości i metody dla formantu MAPISession Obiekt Opis Właściwość DownloadMail Pobiera nowe wiadomości Właściwość LogonUI Wyświetla okno dialogowe logowania Właściwość NewSession Tworzy nową sesję pocztową Właściwość Password Hasło związane z właściwością UserName Właściwość SessionID Identyfikator aktualnej sesji pocztowej Właściwość UserName Profil używany do tworzenia nowej sesji pocztowej Metoda SignOff Wylogowanie użytkownika i zakończenie sesji pocztowej Metoda SignOn Zalogowanie użytkownika do sesji pocztowej Formant MAPIMessages Po otwarciu sesji przez użytkownika za pomocą formantu MAPISession w celu tworzenia nowych wiadomości i przeglądania starych, wysyłania z załącznikami lub bez, odpowiadania na wiadomości, wyświetlania książek adresowych i innych czynności można korzystać z formantu MAPIMessages. Przykład wykorzystania tego formantu znajduje się na rysunku 9.15. Tabela 9.11 zawiera najczęściej używane właściwości i metody dla formantu MAPIMessages. Tabela 9.11. Właściwości i metody dla formantu MAPIMessages Obiekt Opis Właściwość AttachmentName Nazwa pliku załącznika Właściwość MsgCount Ilość wiadomości w zbiorze Właściwość MsgDateReceived Data otrzymania wiadomości Właściwość MsgID Identyfikator wiadomości Właściwość MsgNoteText Tekst wiadomości Właściwość MsgRead Określa, czy wiadomość została przeczytana Właściwość MsgSent Określa, czy wiadomość została wysłana Właściwość MsgSubject Temat wiadomości Właściwość RecipAdress E-mailowy adres odbiorcy Metoda Compose Pisanie wiadomości Metoda Copy Kopiowanie wiadomości Tabela 9.11. Właściwości i metody dla formantu MAPIMessages (ciąg dalszy) Obiekt Opis Metoda Delete Usuwanie wiadomości Metoda Fetch Tworzenie zbioru z wybranych wiadomości Metoda Forward Przesyłanie wiadomości dalej Metoda Reply Odpowiadanie na wiadomość Metoda Save Zapisywanie wiadomości Metoda Send Wysyłanie wiadomości Formant MonthView Formant ten daje użytkownikom możliwość przeglądania i wybierania dat za pomocą kalendarzowego interfejsu (rysunek 9.16). Ilość wyświetlanych miesięcy i kolorystyka formantu mogą być dowolnie modyfikowane. Rysunek 9.16. Przykład formantu MonthView Użytkownicy mają możliwość wybierania pojedynczych dat lub zaznaczania ich blokowo przy użyciu właściwości MultiSelect. Tabela 9.12 zawiera najczęściej używane właściwości i zdarzenia dla formantu MonthView. Tabela 9.12. Właściwości i zdarzenia dla formantu MonthView Obiekt Opis Właściwość DayOfWeek Określa dzień tygodnia Właściwość MinDate/MaxDate Zakres dat wyświetlanych w formancie Tabela 9.12. Właściwości i zdarzenia dla formantu MonthView (ciąg dalszy) Obiekt Opis Właściwość MaxSelCount Maksymalna możliwa ilość dat do zaznaczenia Właściwość MonthBackColor Określa kolor tła miesiąca Właściwość MonthColumns Ilość wyświetlanych kolumn miesięcznych Właściwość MonthRows Ilość wyświetlanych wierszy miesięcznych Właściwość MultiSelect Umożliwia zaznaczanie kilku dat jednocześnie Właściwość SelStart/SelEnd Dolna i górna granica zaznaczenia Właściwość ShowToday Umożliwia użytkownikowi powrót do dzisiejszej daty Właściwość StartOfWeek W skrajnej lewej kolumnie wyświetla dzień tygodnia Właściwość Value Aktualnie wybrana data Zdarzenie DateClick Kliknięcie daty w formancie Zdarzenie DateDblClick Dwukrotne kliknięcie daty w formancie Zdarzenie SelChange Występuje przy nowym wybraniu daty Formant ProgressBar Ważne jest, by w przypadku dłuższych procesów informować użytkownika o jego przebiegu. W przeciwnym razie użytkownik może uznać, że komputer się zawiesił, i zamknąć aplikację. Może to doprowadzić do błędów w programie, utraty danych i tym podobnych problemów. Formant ProgressBar dostarcza użytkownikowi informacji o tym, że komputer jest zajęty i określa w przybliżeniu czas, w jakim proces zostanie zakończony (rysunek 9.17). Możesz dostosowywać wygląd tego formantu, zmieniając jego położenie oraz minimalne i maksymalne wartości. Umożliwia to zmianę długości paska stanu w zależności od czasu trwania procesu. Rysunek 9.17. Przykład formantu ProgressBar Wizualne informowanie użytkownika o przebiegu dłuższego procesu sprawia, iż wydaje się on być krótszy niż jest w rzeczywistości. W przypadku długich procesów powinieneś już na początku w części wypełnić formant. Nie jest to być może zbyt uczciwe, bo nie odzwierciedla rzeczywistego postępu procesu. Jednakże w sytuacji, w której mija dłuższy czas, zanim wypełni się choćby pierwsza część paska postępu, może się zdarzyć, że użytkownik wyłączy komputer myśląc, że się zawiesił. Tabela 9.13 zawiera najczęściej używane właściwości formantu ProgressBar. Tabela 9.13. Właściwości formantu ProgressBar Obiekt Opis Właściwość Min/Max Minimalne i maksymalne wartości formantu Właściwość Orientation Położenie (poziome i pionowe) formantu Właściwość Scrolling Określa, czy postęp jest wyświetlany skokowo, czy w sposób łagodny Zdarzenie Value Wartość formantu. Gdy wartość jest zwiększana, postęp wyświetlany w formancie wzrasta Formant RichText Formant RichText dostarcza użytkownikowi zaawansowanych możliwości formatowania tekstu. W przeciwieństwie do standardowych pól tekstowych formant ten umożliwia stosowanie różnych czcionek i kolorów (rysunek 9.18). Rysunek 9.18. Przykład formantu RichText Możliwości formantu RichText są następujące: ? Łączenie czcionek, stylów, rozmiarów i kolorów. ? Indeksy dolne i górne. ? Formatowanie akapitów. ? Możliwość pracy z dużymi plikami tekstowymi. ? Zdolność dołączania do pola typu memo w Accessie. ? Możliwość dołączania plików graficznych, ikon i dokumentów. Tabela 9.14 zawiera najczęściej używane właściwości, metody i zdarzenia dla formantu RichText. Tabela 9.14. Właściwości, metody i zdarzenia dla formantu RichText Obiekt Opis Właściwość BulletIndent Ustawia bądź pobiera wielkość akapitu Właściwość FileName Nazwa pliku załadowanego do formantu Właściwość MaxLength Maksymalna ilość znaków w formancie Właściwość MultiLine Umożliwia pisanie tekstu w więcej niż jednej linii Właściwość RightMargin Określa prawy margines Właściwość ScrollBars Wyświetla poziomy i pionowy pasek przewijania Właściwość SelAlignment Określa wyrównanie zaznaczonych paragrafów Właściwości SelBold, SelItalics, SelStrikeThru, SelUnderline Formatuje zaznaczony tekst Właściwość SelColor Określa kolor zaznaczonego tekstu Metoda Find Przegląda formant w poszukiwaniu określonego tekstu Metoda LoadFile Ładuje do formantu plik tekstowy lub plik .RTF Metoda SaveFile Zapisuje plik zawarty w formancie Metoda SelPrint Drukuje zaznaczony tekst Metode SelChange Występuje, gdy zmianie ulegnie zaznaczenie tekstu lub pozycja znaku wprowadzania Formant Slider Formant Slider może być wykorzystany do wprowadzania lub wyświetlania danych na skali ciągłej (rysunek 9.19). Modyfikować można przedział zmiany, właściwości ruchu i położenie (poziome i pionowe). Rysunek 9.19. Przykład formantu Slider Tabela 9.15 zawiera najczęściej używane właściwości, metody i zdarzenia dla formantu Slider. Tabela 9.15. Właściwości, metody i zdarzenia dla formantu Slider Obiekt Opis Właściwość LargeChange Określa skok suwaka po naciśnięciu klawiszy Page Up i Page Down oraz kliknięciu jednego z końców suwaka Właściwośc SmallChange Określa skok suwaka po naciśnięciu klawiszy strzałek (lewo–prawo) Właściwość Min/Max Minimalna i maksymalna wartość formantu Właściwość Orientation Położenie formantu (poziome i pionowe) Właściwość SelectRange Określenie wielkości zaznaczenia Właściwość Value Aktualna wartość formantu Metoda ClearSel Usuwa aktualne zaznaczenie formantu Metoda GetNumTicks Pobiera ilość skoków suwaka pomiędzy wartościami Min i Max Zdarzenie Scroll Występuje przy ruchu suwaka Formant StatusBar Formant ten (pasek stanu) jest wykorzystywany w wielu aplikacjach (np. Word i Excel). Dostarcza on użytkownikowi wielu informacji (rysunek 9.20). Rysunek 9.20. Przykład formantu StatusBar Korzystając z właściwości Align, możesz umieścić formant StatusBar w różnych miejscach formularza (u góry, u dołu, po lewej bądź prawej stronie). Aby być w zgodzie z innymi aplikacjami systemu Windows, należałoby umieścić pasek stanu u dołu formularza. Formant StatusBar zawiera obiekty Panel i zbiór Panels, które mogą być użyte do programowego wykonywania czynności. Przykładowo, jeśli użytkownik kliknie określony panel, wykonana zostanie dana czynność. Tabela 9.16 zawiera najczęściej używane obiekty, metody i zdarzenia dla formantu StatusBar. Tabela 9.16. Obiekty, metody i zdarzenia dla formantu StatusBar Obiekt Opis Obiekt Collection Zbiór Panels Obiekt Individual Obiekt Panel jest obiektem na liście Właściwość Align Określa położenie formantu na formularzu (u góry, u dołu, z lewej lub prawej strony) Właściwość SimpleText Ustawia bądź pobiera tekst z formantu, gdy właściwość Style ustawiona jest na Simple Właściwość Style Ustawia właściwość stylu, by wyświetlać jedne lub wszystkie panele Zdarzenie PanelClick Występuje, gdy użytkownik kliknie panel Zdarzenie PanelDblClick Występuje, gdy użytkownik dwukrotnie kliknie panel Formant SysInfo Formant ten umożliwia otrzymywanie informacji o systemie i reagowanie na nie (rysunek 9.21). Może on służyć od kontrolowania następujących informacji systemowych: ? System operacyjny, jego wersja i numer edycji. ? Zdarzenia na pulpicie, wielkość monitora i zmiany rozdzielczości. ? Zdarzenia związane z Plug and Play. ? Właściwości i zdarzenia związane z zarządzaniem energią. Rysunek 9.21. Przykład formantu SysInfo Tabela 9.17 zawiera najczęściej używane obiekty, metody i zdarzenia dla formantu SysInfo. Tabela 9.17. Obiekty, metody i zdarzenia dla formantu SysInfo Obiekt Opis Właściwość ACStatus Wykrywa użycie zasilania prądem zmiennym Właściwość BatteryFullTime Gdy bateria jest w pełni naładowana, określa jej żywotność w sekundach Tabela 9.17. Obiekty, metody i zdarzenia dla formantu SysInfo (ciąg dalszy) Obiekt Opis Właściwość BatteryLifePercent Żywotność baterii w procentach Właściwość BatteryLifeTime Zwraca ilość sekund pozostałej żywotności baterii Właściwość BatteryStatus Stan baterii (niski, średni, wysoki, ładowanie) Właściwość OSBuild Numer wersji systemu operacyjnego Właściwość OSPlatform System operacyjny (Windows 95, Windows NT) Właściwość OSVersion Numer edycji systemu operacyjnego Zdarzenie ConfigChange Występuje w przypadku zmiany profilu sprzętowego Zdarzenie DeviceArrival Występuje w przypadku dodania do systemu nowego sprzętu Zdarzenie PowerStatusChanged Występuje w przypadku zmiany stanu zasilania Zdarzenie PowerSuspend Występuje przed wstrzymaniem pracy komputera Zdarzenie TimeChanged Występuje w przypadku zmiany ustawienia zegara systemowego Formant TabStrip Formant TabStrip przydaje się w sytuacji, gdy pojawia się konieczność umieszczenia wielu formantów na jednym formularzu (rysunek 9.22). Przy jego użyciu formanty mogą być rozmieszczone na różnych zakładkach. Wygląd i położenie formantów na zakładkach może być modyfikowane. Rysunek 9.22. Przykład formantu TabStrip Tabela 9.18 zawiera najczęściej używane obiekty, właściwości, metody i zdarzenia dla formantu TabStrip. Tabela 9.18. Obiekty, właściwości, metody i zdarzenia dla formantu TabStrip Obiekt Opis Obiekt Collection Zbiór Tabs Obiekt Individual Obiekt Tab – pojedyncza zakładka Właściwości ClientHeight, ClientWidth, ClientLeft, ClientRight Zwraca współrzędne obszaru wyświetlania formantu Właściwość ImageList Przyporządkowuje formant ImageList Właściwość MultiSelect Umożliwia wybór kilku obiektów jednocześnie Właściwość Placement Umieszcza zakładki u góry, u dołu, po lewej lub po prawej stronie Właściwość SelectedItem Określa wybraną zakładkę Właściwość Style Modyfikuje wygląd zakładek (przyciski zwykłe bądź płaskie) Metoda DeselectAll Usuwa zaznaczenie zakładek Obiekt Click Występuje po kliknięciu zakładki Formant Toolbar Dzięki temu formantowi możesz utworzyć pasek narzędzi dla aplikacji Accessa. Oddaje on do rąk użytkowników graficzny interfejs, zawierający najczęściej używane obiekty menu (rysunek 9.23). Rysunek 9.23. Przykład formantu Toolbar Formant Toolbar zawiera obiekty Button (przycisk) i zbiór Buttons. Przyciski mogą być programowo dodawane i usuwane z formularza. Istnieje również możliwość napisania kodu, który będzie reagował na zdarzenia (najczęściej na zdarzenie ButtonClick). Tabela 9.19 zawiera najczęściej używane obiekty, właściwości, metody i zdarzenia dla formantu Toolbar. Tabela 9.19. Obiekty, właściwości, metody i zdarzenia dla formantu Toolbar Obiekt Opis Obiekt Collection Zbiór Buttons Tabela 9.19. Obiekty, właściwości, metody i zdarzenia dla formantu Toolbar (ciąg dalszy) Obiekt Opis Obiekt Individual Obiekt Button – pojedynczy przycisk Obiekt Collection Zbiór ButtonMenus Obiekt Individual Obiekt ButtonMenu – rozwijana lista obiektu Button Właściwość Align Wyświetla formant u góry, u dołu, po lewej lub po prawej stronie formularza Właściwość AllowCustomize Umożliwia użytkownikowi dostosowywanie formantu Właściwość BorderStyle Określa wygląd ramki formantu Właściwości ButtonHeight, ButtonWidth Wysokość i szerokość znajdujących się na pasku narzędzi przycisków Właściwość ImageList Przyporządkowuje formant ImageControl Właściwość Style Określa styl formularza (zwykły, transparentny lub tekst na prawo od rysunku) Metoda Customize Umożliwia użytkownikowi dostosowywanie paska narzędzi Metoda RestoreToolbar Przywraca początkowy stan paska narzędzi Obiekt ButtonClick Występuje po naciśnięciu przycisku Obiekt ButtonMenuClick Występuje po naciśnięciu przycisku w menu Formant TreeView Formant TreeView wyświetla hierarchiczną listę – taką, jaka znajduje się w lewym ok.nie Eksploratora Windows. W Eksploratorze hierarchiczna lista folderów może być przeglądana na różne sposoby. Na rysunku 9.24 znajduje się przykład użycia formantu TreeView w formularzu Accessa. Rysunek 9.24. Przykład formantu TreeView Formant TreeView zawiera obiekty Node (węzeł). Każdy obiekt Node zawiera tekst i rysunki. Po hierarchii formantu można poruszać programowo, a także rozwijać i zwijać węzły. Tabela 9.20 zawiera najczęściej używane obiekty, właściwości i zdarzenia dla formantu TreeView. Tabela 9.20. Obiekty, właściwości i zdarzenia dla formantu TreeView Obiekt Opis Obiekt Collection Zbiór Nodes Obiekt Individual Obiekt Node – obiekt w formancie TreeView Właściwość Checkboxes Włącza pola wyboru w formancie Właściwość Indentation Określa szerokość wcięcia Właściwość LabelEdit Umożliwia użytkownikom edycję etykiet węzłów Właściwość LineStyle Określa sposób wyświetlania linii między węzłami Właściwość SelectedItem Zaznaczony węzeł Właściwość Sorted Określa sposób sortowania węzła głównego i węzłów podrzędnych Właściwość Style Określa wygląd każdego z węzłów (tekst, rysunki, plus – minus i linie) Zdarzenie AfterLabelEdit Występuje, gdy użytkownik dokona edycji etykiety węzła Zdarzenie Collapse Występuje, gdy węzeł zostanie zwinięty Zdarzenie Expand Występuje, gdy węzeł zostanie rozwinięty Zdarzenie NodeClick Występuje po kliknięciu węzła Obiekt Node posiada własny zestaw przydatnych właściwości (Child, FirstSibling, LastSibling, Previous, Parent, Next i Root). Formant UpDown Formant UpDown ułatwia użytkownikom zmianę wartości liczbowych za pomocą myszy. Składa się on z pary strzałek, które użytkownik może klikać, by żądana wartość wzrosła bądź zmalała (rysunek 9.25). Formant UpDown można bez trudu połączyć z innym formantem (np. polem tekstowym), za pomocą właściwości BuddyControl. Nie ma konieczności pisania dodatkowego kodu. Dzięki użyciu właściwości BuddyControl dwa formanty będą ze sobą współpracować. Gdy użytkownik kliknie jedną ze strzałek formantu UpDown, wartość w polu tekstowym automatycznie się zmieni. Rysunek 9.25. Przykład formantu UpDown Tabela 9.21 zawiera najczęściej używane właściwości i zdarzenia dla formantu UpDown. Tabela 9.21. Właściwości i zdarzenia dla formantu UpDown Obiekt Opis Właściwość Alignment Umieszcza formant UpDown po lewej lub prawej stronie formantu związanego Właściwość AutoBuddy Określa, czy użyto właściwości BuddyControl do ustawienia formantu związanego Właściwość BuddyControl Określa nazwę formantu, który ma być formantem związanym Właściwość BuddyProperty Określa właściwości, dzięki którym można zsynchronizować formant UpDown z formantem związanym Właściwość Increment Określa wielkość zmiany formantu Właściwość Min/Max Minimalna i maksymalna wartość formantu Właściwość Orientation Określa położenie formantu (poziome lub pionowe) Właściwość SyncBuddy Określa, czy występuje synchronizacja właściwości Value formantu UpDown z formantem związanym Właściwość Value Aktualna pozycja wartości przewijanej Zdarzenie Change Występuje przy zmianie właściwości Value Zdarzenie DownClick Występuje po naciśnięciu strzałki w dół lub w lewo Zdarzenie UpClick Występuje po naciśnięciu strzałki w górę lub w prawo Formant WebBrowser Formant ten służy do umieszczania przeglądarki Microsoft Internet Explorer wewnątrz formularzy Accessa (rysunek 9.26). Jaki jest tego cel, skoro większość użytkowników już posiada przeglądarkę na swoim komputerze? ? Przeglądarka ta jest udostępniana użytkownikom bez konieczności opuszczania Accessa. ? Ogranicza dostęp użytkownika do wybranych stron WWW. Kierownictwo niektórych firm zauważyło znaczną utratę produktywności swoich pracowników, spowodowaną przeglądaniem stron WWW, niezwiązanych z ich obowiązkami. Rysunek 9.26. Przykład formantu WebBrowser Dzięki formantowi WebBrowser można użytkownikom nadać dostęp do określonych stron lub uniemożliwić dostęp do niektórych z nich. Jeśli na Twoim komputerze zainstalowany jest Internet Explorer (w wersji 3 lub wyższej), zainstalowany jest również formant WebBrowser. Formant ten nie może być rozpowszechniany osobno w aplikacjach. Musisz więc sprawdzić, czy użytkownicy posiadają taką przeglądarkę lub przekazać im całego Internet Explorer’a. Tabela 9.22 zawiera najczęściej używane właściwości, metody i zdarzenia dla formantu WebBrowser. Tabela 9.22. Właściwości, metody i zdarzenia dla formantu WebBrowser Obiekt Opis Właściwość AdressBar Pokazuje pasek z adresem strony Właściwość FullScreen Maksymalizuje okno Właściwość LocationName Pobiera nazwę strony/pliku Właściwość LocationURL Pobiera pełną ścieżkę dostępu do strony/pliku Właściwość MenuBar Pokazuje pasek menu Właściwość Type Pobiera typ dokumentu w formancie Metoda GoBack Powrót do poprzedniej strony Metoda GoForward Przejście do następnej strony Metoda GoHome Przejście do strony początkowej Metoda GoSearch Przejście do strony z wyszukiwarką Metoda Navigate Odświeża aktualną stronę Metoda Refresh Zatrzymuje otwieranie strony Zdarzenie DownloadBegin Występuje po rozpoczęciu otwierania strony Tabela 9.22. Właściwości, metody i zdarzenia dla formantu WebBrowser (ciąg dalszy) Obiekt Opis Zdarzenie DownloadComplete Występuje po zakończeniu otwierania strony Zdarzenie StatusChangeText Występuje po zmianie tekstu na pasku stanu Zdarzenie TitleChange Występuje po zmianie tytułu dokumentu Dystrybucja formantów ActiveX Gdy przekazujesz użytkownikom aplikację Accessa, musisz do niej dołączyć wszystkie formanty ActiveX. W przeciwnym razie aplikacja nie będzie działać prawidłowo. Każdy użyty formant ActiveX musi być poprawnie zainstalowany i zarejestrowany przez użytkownika. Najłatwiejszym sposobem na udostępnianie formantów jest użycie narzędzia VBA Package and Deployment Wizard. Aby tego dokonać, z menu Add-Ins Edytora Visual Basic wybierz pozycję Add-In Manager. Zaznacz VBA Package and Deployment Wizard. U dołu formularza zaznacz sposób, w jaki narzędzie ma zostać uruchomione, a następnie kliknij OK. Kreator przeprowadzi Cię przez wszystkie kroki i pomoże utworzyć program instalacyjny dla Twojej aplikacji. Kreator ten dołączy wszystkie wymagane formanty ActiveX i inne niezbędne pliki. Po uruchomieniu tego programu przez ostatecznego użytkownika i zainstalowaniu na jego komputerze aplikacji wraz z powiązanymi z nią plikami aplikacja będzie działać poprawnie. VBA Package and Deployment Wizard dokonuje również odpowiednich zapisów w rejestrze systemowym komputera użytkownika. Rozdział 10. Tworzenie raportów W tym rozdziale: ? Czym są raporty? ? Struktura raportów w Accessie. ? Tworzenie prostych raportów przy użyciu kreatora. ? Dostosowywanie raportów. ? Praca z podraportami. ? Tworzenie prostych etykiet adresowych. ? Publikowanie raportu. ? Modyfikowanie raportu podczas jego działania. ? Programowe tworzenie raportów. ? Wskazówki. Po zakończeniu projektowania struktury danych w aplikacji i po stworzeniu formularzy, które ułatwią użytkownikom pracę z danymi, nadszedł czas na stworzenie raportów. Raporty to najbardziej widoczna część aplikacji. Ludzie, którzy nigdy nie zobaczą żadnego formularza i nie mają pojęcia, jak poradziłeś sobie z bezpieczeństwem i układem danych, będą oglądać stworzone przez Ciebie raporty. Tak się składa, że dowiesz się, czy Twoja aplikacja jest dobra, jeśli będziesz często proszony o nowe raporty lub modyfikacje już istniejących. Praca ta jest równie przyjemna co męcząca, jako że pośród wszystkich obiektów w Accessie raporty stawiają przed programistami największe wyzwanie. Czym są raporty? W tym rozdziale podzielimy raporty na części składowe i omówimy działanie każdej z nich. Przyjrzymy się również kilku sztuczkom, które sprawią, że nasze raporty z łatwością będą wykonywały z pozoru trudne zadania. W przypadku zadań, których nie można wykonać w prosty sposób, pokażemy, jak można modyfikować raport przy użyciu kodu VBA tak, by raport wykonywał prawie każde Twoje polecenie. Zajmiemy się również raportami związanymi oraz niezwiązanymi, formantami i podraportami. Raporty powstały jako narzędzie do tworzenia wydruków. Dlatego też ich możliwości są do pewnego stopnia ograniczone. W przeciwieństwie do formularzy raporty nie są interaktywne, tak więc po ich wydrukowaniu bądź przejściu do widoku podgląd wydruku użytkownik nie ma możliwości zmiany wartości lub źródeł danych. Ostateczny wygląd raportu zależy od sterownika drukarki, ponieważ to, co widzimy, musi być zgodne z parametrami drukarki i rodzajem użytego papieru. Pomimo tych ograniczeń, raporty Accessa to bardzo elastyczne narzędzia do prezentacji danych. Kluczem do ujarzmienia ich zdolności jest poznanie obiektu raport i wszystkich jego elementów. Najlepszym sposobem, by to osiągnąć, jest przyjrzenie się im wszystkim z osobna. Struktura raportów w Accessie Raporty w Accessie podzielone są na cztery główne części (sekcje): Nagłówek/Stopka raportu, Nagłówek/Stopka strony, Nagłówek/Stopka sekcji i szczegóły. Sekcje te porządkują dane w raporcie. Pierwszym w kolejności wydruku elementem raportu jest Nagłówek/Stopka raportu. Jest tylko jeden taki element. Stopka raportu drukowana jest po wszystkich danych, lecz przed stopką strony (mimo, iż w widoku Projekt wygląda to inaczej). Każda strona w raporcie może mieć Nagłówek/Stopkę strony. Mimo iż masz dostęp tylko do jednej sekcji Strona w widoku Projekt, sekcja ta drukowana jest na każdej stronie raportu. Później pokażemy jak modyfikować Nagłówek/Stopkę strony, by wyglądała inaczej na każdej stronie. Nagłówki/Stopki sekcji pojawiają się, gdy umieszczasz w raporcie elementy grupowane. W raporcie może być maksymalnie dziesięć takich sekcji. Niejednokrotnie sprawiają one wiele trudności projektantom raportów. Pokażemy, jak można nimi zarządzać, by uzyskiwać przydatne informacje. Ostatnia z omawianych sekcji – Szczegóły – wyświetla najbardziej szczegółowe informacje w raporcie. Istnieje tylko jedna sekcja Szczegóły i umieszczona jest między wszystkimi nagłówkami i stopkami sekcji, pośrodku widoku Projekt. Rysunek 10.1 przedstawia sekcje raportu w widoku Projekt. Najprostszym sposobem prezentowania danych w raporcie jest umieszczenie w poszczególnych sekcjach związanych formantów. Jednakże jest możliwe umieszczenie w dowolnej sekcji innego raportu tak, by pełnił funkcję podraportu. W tym rozdziale poznasz nowe opcje oraz kwestie związane z użyciem podraportów w Accessie 2000. Wreszcie obiekt Raport, który jak wszystkie obiekty Accessa 2000 jest pełen właściwości i zdarzeń, które umożliwią dostosowanie i automatyzację działania raportów. Od czasu Accessa 97 w raportach nie zmieniło się zbyt wiele, jednak przyjrzymy się zaletom tych właściwości i zdarzeń, by móc tworzyć doskonałe raporty w Accessie 2000. Rysunek 10.1. Widok Projekt raportu Kategorie i Produkty Tworzenie prostych raportów przy użyciu kreatora Kreator raportów jest chyba najbardziej przydatnym z kreatorów Accessa i mimo iż mało prawdopodobne jest, że da Ci raport idealnie odpowiadający Twoim potrzebom, to prawdopodobnie zaoszczędzi Ci 90% pracy w 90% raportów. Co więcej, zadania, które wykona, to najbardziej pracochłonne i nużące z czynności związanych z tworzeniem raportów. Kreator Raportów może jedynie tworzyć nowe raporty. Po utworzeniu raportu modyfikacji możesz dokonywać wyłącznie ręcznie Aby utworzyć raport przy użyciu Kreatora raportów wystarczy z okna dialogowego Nowy raport wybrać pozycję Kreator raportów (rysunek 10.2). 28. Wybierz źródło danych (w naszym przykładzie używamy tabeli Kategorie) i kliknij przycisk OK. 29. Kreator poprosi o podanie pól, które chcesz umieścić w raporcie. Możesz je wybierać pojedynczo lub umieścić w raporcie wszystkie pola jednocześnie. Kolejność, w jakiej wybierasz pola, ma wpływ na sortowanie i umieszczenie formantów w raporcie. 30. W kolejnym, przedstawionym na rysunku 10.3, oknie dialogowym możesz określić rodzaj grupowania w raporcie. Ponieważ nasz przykład jest oparty o jedną tabelę, grupowanie nie jest zbyt użyteczne. Możesz przejść do kolejnego okna. Rysunek 10.2. Okno dialogowe Nowy raport z wybranymi Kreatorem raportów i tabelą Kategorie Rysunek 10.3. Ustawienia właściwości Sortowanie i Grupowanie W oknie tym mamy możliwość ustawienia sposobu sortowania raportu. Pola mogą być sortowane maksymalnie po czterech polach w kolejności rosnącej bądź malejącej. Wybierz pola do sortowania: IDkategorii oraz NazwaProduktu. 31. Po wybraniu kolejności sortowania możesz zdecydować o układzie raportu: kolumnowy, tabelaryczny i wyjustowany. Możesz także wybrać orientację drukowanego raportu (poziomą bądź pionową). Kolejna opcja umożliwia dostosowanie szerokości pól tak, by były widoczne na stronie. Nie chodzi tu o przekształcenie czcionki do odpowiedniego rozmiaru, jak to ma miejsce w przypadku podobnej opcji programu Microsoft Excel. W przypadku Accessa wybranie tej opcji powoduje zmianę szerokości formantów, by mieściły się na stronie. W rezultacie dane mogą stać się nieczytelne, bo zostaną obcięte, jeśli szerokość formantu będzie zbyt mała. W następnym oknie masz do wyboru kilka stylów. Zmieniają one nagłówki, etykiety oraz sekcje raportu i mogą przy niewielkim wysiłku z Twojej strony nadać raportowi elegancki i estetyczny wygląd. 32. W ostatnim oknie dialogowym powinieneś podać nazwę dla raportu i wybrać, czy chcesz zobaczyć raport, czy modyfikować go w widoku Projekt. Mimo iż Kreator utworzył raport, możesz modyfikować go w dowolny sposób, kiedy tylko zechcesz. Kreator ten może również tworzyć raporty oparte na więcej niż jednym źródle danych. Jeśli utworzyłeś relację między tabelami w bazie danych, Kreator raportów utworzy dla raportu odpowiednie wyrażenie SQL. 33. Korzystając z kreatora, utwórz ponownie nowy raport. Przejdź do okna dialogowego, gdzie wybierałeś pola, i dodaj pole NazwaKategorii z tabeli Kategorie (rysunek 10.4). Rysunek 10.4. Wybieranie pól w Kreatorze raportów 34. Z rozwijanej listy Tabele/Kwerendy wybierz tabelę Produkty, a następnie wybierz pole NazwaProduktu (rysunek 10.5). Rysunek 10.5. Oba pola zostały dodane 35. Przejdź przez okna dialogowe i ustaw sortowanie na pole NazwaProduktu. 36. Nazwij raport „Kategorie i Produkty” i zobacz, jak wygląda. W widoku Projekt raportu zauważysz, że Kreator raportów utworzył wyrażenie SQL, korzystając z relacji powstałych w fazie projektowania bazy danych Northwind. Dostosowywanie raportów Nie często się zdarza, by raport utworzony przy użyciu kreatora idealnie odpowiadał Twoim potrzebom. By zaoszczędzić czas, powinieneś w każdej sytuacji korzystać z Kreatora raportów, jednak wiedzy o dostosowywaniu raportów nie da się niczym zastąpić. W kilku krokach i dokonując kilku obliczeń możesz zmienić raport Kategorie i Produkty w raport pokazujący zamówienia produktów według kategorii. Będzie on posiadał źródło rekordów oparte na kilku tabelach, sortowanie, grupowanie, obliczenia oraz nagłówki i stopki. To elementy, których będziesz używał w 75% raportów Accessa. Zmiana źródła rekordów w raporcie Pierwszym krokiem w modyfikowaniu raportu jest zmiana jego źródła rekordów ( rysunek 10.6). Trudno byłoby dokonać znaczących zmian w raporcie, nie uzyskując właściwych rekordów i pól. Rysunek 10.6. Właściwość Źródło rekordów w oknie właściwości raportu W oknie właściwości raportu wybierz właściwość Źródło rekordów i kliknij przycisk z wielokropkiem (...), aby uruchomić Konstruktora kwerend ( rysunek 10.7). Do kwerendy dodaj tabelę Opisy zamówień. Z tabeli Produkty dodaj również pola Ilośćjednostkowa i IDproduktu. Zamknij Konstruktora kwerend. Teraz, gdy źródło rekordów zostało zmienione, możesz zmodyfikować raport tak, by przedstawiał dane w użyteczny sposób. Rysunek 10.7. Konstruktor kwerend Zmiana struktury grupowania w raporcie Najbardziej znaczącą ze zmian, jakich musisz dokonać, jest zmiana struktury grupowania w raporcie. Gdy dokonujesz grupowania, każesz raportowi zebrać razem wskazane dane i przedstawić je w blokach. Bloki te nazywane są również pasmami. Możesz tworzyć je i modyfikować poprzez okno dialogowe Sortowanie i grupowanie. Po utworzeniu pasma grupującego masz do dyspozycji kilka opcji: ? Pole/Wyrażenie – pole lub wyrażenie, które decyduje o grupowaniu raportu. ? Porządek sortowania – sposób prezentowania grupowania. Do wyboru masz Rosnąco lub Malejąco. ? Nagłówek grupy – po umieszczeniu grupy w raporcie możesz zdecydować, czy przed danymi ma znajdować się wolna przestrzeń, w której zazwyczaj umieszcza się informacje o grupowanych wartościach. ? Stopka grupy – sekcja ta znajduje się po grupie danych. Zazwyczaj zawiera obliczenia i podsumowania danych w grupie. ? Grupuj według – właściwość ta określa, co będzie decydowało o grupowaniu. Przy ustawieniu Każda wartość dane będą grupowane według wartości całych elementów, podczas gdy ustawienie Pierwsze znaki spowoduje grupowanie tylko według pierwszych znaków elementów. Właściwość ta działa łącznie z właściwością Przedział grupowania. ? Przedział grupowania – gdy właściwość Grupuj według ustawiona jest na Interwał, przedział grupowania określa ilość znaków, która zostanie użyta. Tabela 10.1 zawiera dostępne wartości oraz sytuacje, w których można je wykorzystać. Tabela 10.1. Wartości przedziału grupowania i ograniczenia w ich stosowaniu Ustawienie Wartość Ograniczenie Każda wartość 0 Dowolny typ danych Znaki przedrostka 1 Tylko dla pól tekstowych Rok 2 Tylko dla pól daty Kwartał 3 Tylko dla pól daty Tabela 10.1. Wartości przedziału grupowania i ograniczenia w ich stosowaniu (ciąg dalszy) Ustawienie Wartość Ograniczenie Miesiąc 4 Tylko dla pól daty Tydzień 5 Tylko dla pól daty Dzień 6 Tylko dla pól daty Godzina 7 Tylko dla pól daty Minuta 8 Tylko dla pól daty Interwał 9 Tylko dla pól liczbowych Gdy decydujesz się na grupowanie wyrażenia, Access nie będzie w stanie określić jego wyniku, gdy raport będzie w widoku Projekt. W takim przypadku, Access przedstawi wszystkie możliwe opcje właściwości Grupuj według i Przedział grupowania. Upewnij się, że wybrałeś opcję, która będzie odpowiednia dla tego wyrażenia. ? Trzymaj razem – właściwość ta dotyczy drukowanego raportu i sposobu, w jaki Access będzie próbował zmieścić dane na tej samej stronie. Wartości dla tej właściwości i efekt ich działania zawiera tabela 10.2. Tabela 10.2. Wyjaśnienie ustawień właściwości Trzymaj razem Ustawienie Wartość Opis Nie 0 Podział strony występuje w zależności od umiejscowienia nagłówków, stopek i danych. Całą grupę 1 Access próbuje umieścić nagłówki, stopki i dane na jednej stronie. Z pierwszym szczegółem 2 Access próbuje wydrukować nagłówek grupy na tej samej stronie, co pierwszy rekord szczegółowy. Umieszczenie grupowania w raporcie Aby aktywować Grupowanie, wystarczy ustawić nagłówek, stopkę lub oba te elementy. Po wykonaniu tej czynności, w oknie Sortowanie i grupowanie obok nazwy pola pojawi się mała ikona, a w raporcie w widoku Projekt wyświetlona zostanie nowa sekcja. Każdy formant umieszczony w tej sekcji będzie tworzył grupę opartą na jego wartościach, zależną od wybranych ustawień dodatkowych. W raporcie sumującym sprzedane jednostki produktu w poszczególnych kategoriach grupowanie musi się odbywać według produktów. Najlepiej do tego celu wykorzystać unikatowy identyfikator. Mimo iż poniższy przykład funkcjonowałby równie dobrze z Nazwą Produktu, w rzeczywistości produkty mogą występować w różnych rozmiarach, wagach i konfiguracjach, lecz pod tą sama nazwą. Użycie pola ID Produktu umożliwi raportowi odróżnienie takich produktów. 37. Z menu Widok wybierz Sortowanie i Grupowanie. Zmień właściwość sortowania NazwaProduktu na IDproduktu i ustaw właściwość Nagłówek grupy na Tak. Utwórz także Stopkę grupy dla pola kategoria. Elementy te wystarczą do stworzenia pogrupowanego raportu o kategoriach i produktach. 38. Z listy pól wybierz IDproduktu i umieść w Nagłówku IDproduktu, na prawo od formantu IDkategorii w Nagłówku Kategorii. Możesz wyciąć i wkleić etykietę formantu IDproduktu do Nagłówka strony. 39. Przesuń formant NazwaProduktu z sekcji Szczegóły do Nagłówka IDproduktu. Będziesz musiał połączyć go z jego etykietą. Otrzymujemy raport, który zbiera wszystkie kategorie, wielkości ich sprzedaży i tworzy z nich listę. W tej formie raport przedstawia jedynie listę sprzedanych produktów w każdej kategorii, bez podania wielkości sprzedaży. Do tego celu należy stworzyć wyrażenie. Użycie funkcji w raporcie Aby otrzymywać w raporcie właściwe i pełne informacje, będziesz czasami zmuszony do pisania funkcji, które będą w raporcie wykonywać obliczenia lub inne czynności. Umieszczenie w raporcie obliczeń może również wpłynąć na poprawę jego funkcjonowania. Jeśli masz do wyboru umieszczanie funkcji w raporcie lub w podlegającej mu kwerendzie, powinieneś rozważyć to pierwsze rozwiązanie. Umożliwi to zmniejszenie ilości wykonywanych obliczeń. Teraz opiszemy użycie funkcji w raporcie. Użycie funkcji obliczeniowych Obliczenia w raporcie nie różnią się od obliczeń wykonywanych w innych obiektach Accessa. Jedyna różnica polega na tym, że w raporcie to samo wyrażenie, w zależności od sekcji, w której znajduje się formant, może dać inne wyniki. Przyczyna tego faktu jest prosta. Gdy Access przetwarza dane, by utworzyć żądane grupowania, w rzeczywistości przetwarza różne dane. Więc wyrażenie Suma ([IlośćJednostkowa]) umieszczone w nagłówku IDproduktu zwróci wartość sprzedaży każdego z produktów. Jeśli umieścimy to wyrażenie w stopce Kategorii, otrzymamy wartość sprzedaży w danej kategorii. Aby zobaczyć jak to wygląda w praktyce, utwórz pole tekstowe w nagłówku IDproduktu i wpisz wyrażenie Suma ([IlośćJednostkowa]) Mimo iż raport nie zawiera formantu o nazwie „IlośćJednostkowa”, pole takie znajduje się w źródle danych i może być użyte w wyrażeniu. Skopiuj formant do stopki Kategorii. Przejdź do widoku Podgląd wydruku, powinieneś wtedy zobaczyć taki sam rezultat jak na rysunku 10.8. Rysunek 10.8. W zależności od położenia wyrażenia, jego wynik zmienia się Użycie Funkcji Immediate IF Inną, bardzo użyteczną funkcją, którą można wykorzystać w raporcie, jest funkcja Immediate IF (IIF()). Funkcja ta umożliwia wykonanie testu If...Then...Else bez konieczności pisania kodu. Sprawdza się ona, gdy należy podsumować dane bądź podkreślić znaczenie poszczególnych rekordów w raporcie. Zawiera trzy argumenty: warunek, czynność wykonywaną, gdy warunek jest spełniony oraz czynność wykonywaną, gdy warunek nie jest spełniony. Argumenty oddzielane są przecinkiem. Aby użyć tej funkcji, napisz warunek, który może być spełniony lub nie (przykładowo, [suma of ilośćjednostkowa]>=500). Drugim argumentem jest zazwyczaj wartość, jaka jest wyświetlana, gdy warunek został spełniony (np. „Powyżej”), a trzecim argumentem jest wartość, jaka jest wyświetlana, gdy warunek nie jest spełniony (np. „Poniżej” lub brak reakcji). Istnieje możliwość zagnieżdżenia funkcji IIF w innej funkcji, tak więc gdy jeden warunek jest spełniony, przeprowadzany jest kolejny test i tak dalej. Funkcje IIF powinny być używane dość rzadko, gdyż mogą spowalniać pracę raportu. Raport może wykorzystywać procedurę IIF do zaznaczania tych produktów, w przypadku których sprzedaż była równa lub przekroczyła 500 jednostek. Aby to uczynić, z prawej strony nagłówka IDproduktu umieść pole tekstowe i w jego źródle danych wpisz następującą formułę: =IIF ([Suma of Ilośćjednostkowa]>=500, "Powyżej", "") Użycie własnych funkcji w module raportu Zdarza się, że wyrażenie staje się zbyt złożone, by umieścić je w zwykłej funkcji IIF(). Gdy taka sytuacja ma miejsce, możesz utworzyć funkcję, która będzie dokładnie odpowiadać Twoim potrzebom, i odwołać się do niej w raporcie. Przykład na wydruku 10.1 przedstawia, jak można taką funkcję napisać w module raportu i odwołać się do niej z umieszczonego w raporcie formantu. Wydruk 10.1. Funkcja w module raportu ' Jak zamienić wartość na ciąg Function HiLowTest(dblQuantity As Double) As String If dblQuantity >= 500 Then HiLowTest = "Powyżej" Else HiLowTest = "Poniżej" End If End Function Będąc w widoku Projekt raportu, z menu Widok wybierz Kod programu. Spowoduje to otwarcie modułu raportu, w którym możesz tworzyć procedury i funkcje wykorzystywane w tym raporcie. Teraz możesz zamienić funkcję IIF() na: =HiLowTest ([Suma of Ilośćjednostkowa]) Dzięki temu będziesz w stanie lepiej kontrolować to, co dzieje się w danym momencie w formancie, gdyż możesz nadawać funkcjom znaczące nazwy. Umieszczenie funkcji w formancie zapewnia jednocześnie zachowanie ciągłości, jeśli wykorzystujesz te same obliczenia w różnych miejscach raportu. Użycie własnych funkcji w osobnym module Zdarza się również, że obliczenia wykonywane w raporcie wykorzystywane są również w formularzu i w kwerendach. W takich przypadkach dobrze jest napisać funkcję w osobnym module tak, by kwerendy, formularze i raporty danej aplikacji mogły zawsze otrzymywać zbieżne wyniki. Poniższy przykład przedstawia podstawową funkcję, która poprawia pisownię danego ciągu znaków. Do tego rodzaju funkcji można odwoływać się z różnych miejsc w aplikacji. Użyjemy tu nowej funkcji VBA Accessa – Split(). Funkcja ta, w oparciu o wybrany ogranicznik (domyślnie jest nim znak spacji), podzieli ciąg na elementy tablicy. Funkcja ta może mieć wiele zastosowań w Accessie 2000. W tym przypadku posłuży do zamiany w nazwach produktów małych liter na duże. Funkcja ta jest bardzo prosta. Traktuje ciąg jako argument i dzieli go na elementy tablicy (varArray). Następnie, przy użyciu funkcji UCase(), zamienia pierwszą literę każdego słowa na dużą. Aby zwrócić słowa z zamienionymi literami, funkcja korzysta z funkcji Left i Right, które umożliwiają oddzielenie pierwszej litery z lewej strony słowa. Później te grupy liter są ponownie łączone w taki sposób, by znów tworzyły całe słowa. W ten sam sposób łączone są elementy tablicy, by znów tworzyły jeden ciąg, lecz już z poprawną pisownią. Wydruk 10.2 przedstawia, jak to się dzieje. Wydruk 10.2. Zmiana małych liter na duże i użycie nowej funkcji Split Function MakeProper(str As String) As String On Error GoTo MakeProper_Err Dim vararray As Variant Dim i As Integer Dim strTemp As String If Len(str) = 0 Then Resume MakeProper_Exit End If ' Najpierw zamień wszystkie litery na małe str = LCase(str) ' Split() wypełnia tablicę częściami ciągu ' Split() używa spacji jako domyślnego ogranicznika vararray = Split(str) ' Przejdź przez tablicę I zamieniaj każdą z pierwszych liter na ' na dużą oraz utwórz strTemp For i = 0 To Ubound(vararray) strTemp = strTemp & UCase(Left(vararray(i), 1)) & _ Right(vararray(i), Len(vararray(i)) - 1) & " " Next ' Usuń zbędne spacje MakeProper = Trim(strTemp) MakeProper_Exit: On Error Resume Next Exit Function MakeProper_Err: MakeProper = "" Resume MakeProper_Exit End Function Użycie konkatenacji Konkatenacja (łączenie) jest niezwykle często wykorzystywana w zaawansowanych raportach. Umożliwia ona łączenie nazwisk i adresów tak, by można je było łatwo drukować i prezentować. Gdy łączysz dwa elementy danych, nie mogą one już być przetwarzane osobno. Innymi słowy, formularz pokazujący połączone imię i nazwisko klienta nie może być wykorzystywany (bez pisania dużej ilości kodu) do wprowadzania nowych nazwisk. Konkatenacja wykonywana jest przy użyciu operatora konkatenacji, znaku [&]. Można również używać znaku [+], lecz formuły łączące numery klientów z numerami kont mogą być wówczas mylące dla programisty. Więcej zastosowań konkatenacji opiszemy w przedstawionym w dalszej części tego rozdziału przykładzie dotyczącym etykiet adresowych. Przykład: ="Access" & Space (1) & "2000" & Space (1) & _ "Księga" & Space (1) & "Eksperta" zwraca "Access 2000 Księga Eksperta" Możesz sprawdzić działanie tej funkcji w oknie Immediate. Z menu Widok modułu wybierz Immediate Window lub naciśnij klawisze Ctrl+G. W oknie wpisz ?MakeProper ("access 2000 księga eksperta") I naciśnij Enter. Jeśli wszystko zostało poprawnie wprowadzone, powinieneś otrzymać „Access 2000 Księga Eksperta”. Podczas dokonywania konkatenacji musisz zwrócić uwagę na składnię w następujących przypadkach: ? Jeśli w nazwach pól występują spacje, nazwy te muszą być umieszczone w kwadratowych nawiasach (na przykład [ID Zamówienia]). Jednakże dla zachowania przejrzystości dobrze jest używać kwadratowych nawiasów w każdym przypadku. ? Ciągi tekstów muszą być umieszczone w cudzysłowie ("Uwaga"). Rozważ także użycie Chr(34), gdy masz do czynienia z cudzysłowem w kodzie. ? Daty muszą być umieszczone między znakami krzyżyka (#7/27/20000#). Następnym krokiem jest wykorzystanie tej funkcji w raporcie. Spowoduje ona zmianę pisowni nazw produktów z małych liter na duże. W widoku Projekt raportu zmień właściwość źródła formantu NazwaProduktu na: =MakeProper ([NazwaProduktu]) W niektórych przypadkach to wystarczy. Jednakże w tym przypadku, sprawa nie jest taka prosta. Ponieważ formant ten nosi taką samą nazwę jak pole w źródle rekordów raportu, rezultatem funkcji będzie błąd. Oto jeden z powodów, dla których warto przestrzegać przyjętej konwencji nazewnictwa podczas tworzenia formantów w formularzach i raportach. Ponieważ do tworzenia raportu korzystałeś z kreatora, nie miałeś wiele do powiedzenia przy nazywaniu jego formantów. Teraz masz możliwość zmiany nazwy tego formantu. Ponieważ NazwaProduktu jest polem tekstowym, powinieneś zmienić jego nazwę na txtNazwaProduktu. Gdy będziesz teraz przeglądał raport w widoku Podgląd wydruku (jak na rysunku 10.9), zauważysz, że w niektórych przypadkach nazwa produktów została zmieniona. Jak dotąd nauczyłeś się tworzyć prosty raport oraz trochę bardziej skomplikowany przy użyciu kreatora. Wiesz już, jak modyfikować raport po jego utworzeniu. Dowiedziałeś się, co to grupowanie, obliczenia i konkatenacja oraz jak wykorzystywać funkcje w raportach. Tematy te obejmują 90% tworzenia raportów w bazie danych Accessa. Praca z podraportami Tak jak w formularzach można było umieszczać podformularze, tak w raportach można umieszczać podraporty. Podraport jest to raport umieszczony wewnątrz innego raportu, najczęściej służący do pokazywania powiązanych rekordów. Może on być również wykorzystywany do pokazywania tego samego podzestawu danych w różnych raportach. Używając podraportu, możesz korzystać z elastyczności, jaką dają Ci dwa raporty. Rysunek 10.9. Pierwsze litery nazw produktów zostały zmienione Gdy między rekordami w raporcie głównym a rekordami w podraporcie istnieje relacja jeden-do-wielu, główny raport nazywany jest raportem nadrzędnym, a podraport podrzędnym. Mimo iż podobny efekt można często osiągnąć dzięki grupowaniu raportu, podraporty przydają się w sytuacji, gdy chcesz wydrukować rekordy z kilku różnych tabel. Rysunek 10.10 przedstawia kategorię (Napoje) z bazy Northwind i jej podraport o poszczególnych produktach. Rysunek 10.10. Czwarta strona raportu Katalog w bazie Northwind przedstawia elastyczność, jaką dają podraporty Tworzenie prostego podraportu W typowym podraporcie istnieje relacja jeden-do-wielu między rekordami podrzędnymi a nadrzędnymi. Zapisz, które z pól uczestniczą w relacji między dwiema tabelami lub kwerendami. 40. Utwórz raport dla rekordów nadrzędnych. Będzie to raport główny. 41. Utwórz następny raport dla rekordów podrzędnych. Będzie to podraport. 42. W widoku Projekt głównego raportu wyłącz kreator (odpowiedni przycisk znajduje się w przyborniku) i użyj narzędzia Podraport. W miejscu, gdzie chcesz go umieścić, rozciągnij prostokąt. 43. Jako właściwość podraportu Obiekt źródłowy ustaw nazwę podraportu utworzonego w punkcie 3. 44. Jeśli połączone pola, które wcześniej zapisałeś, mają takie same nazwy, Access automatycznie wypełni właściwości Nadrzędne pole łączące i Podrzędne pole łączące. Jeśli nazwy ich są różne, nazwa powiązanego pola głównego raportu powinna być wpisana we właściwości Nadrzędne pole łączące, a we właściwości Podrzędne pole łączące powinna zostać wpisana nazwa odpowiadającego mu pola podraportu. Jeśli łącze wymaga więcej niż jednego pola, oddziel je przecinkiem. We właściwości Podrzędne pole łączące należy umieścić nazwę związanego pola, a nie nazwę formantu wyświetlającego to pole. Natomiast we właściwości Nadrzędne pole łączące można się posłużyć nazwą odpowiedniego formantu. Jeśli raport główny i podraport są ze sobą powiązane, to, aby raport działał, właściwości Nadrzędne pole łączące i Podrzędne pole łączące muszą być ustawione poprawnie. Istnieje możliwość utworzenia konstrukcji raport główny – podraport bez tworzenia między nimi relacji. W takich przypadkach można używać wykorzystywanych w wielu raportach odnośników lub bloków adresowych, lecz wyświetlanych jako podraport w celu zapewnienia spójności i przejrzystości. Można nawet utworzyć raport główny, który nie będzie zawierał żadnych rekordów. Sposób wyświetlania podraportów został w Accessie 2000 znacznie poprawiony. We wcześniejszych wersjach podraport przedstawiany był jako puste pole w widoku Projekt głównego raportu. Teraz wyświetla on wiele przydatnych informacji o używanych w podraporcie polach. Co więcej, istnieje możliwość edycji podraportu w widoku Projekt raportu głównego ( rysunek 10.11). Możliwości modyfikowania właściwości i formantów podraportu są dużo większe niż kiedyś. Pozwala to zaoszczędzić dużo czasu i wysiłku. We wcześniejszych wersjach, aby modyfikować podraport, programista musiał otwierać go w osobnym oknie, z poziomu głównego okna bazy danych. Rysunek 10.11. Modyfikowanie formantów podraportu Istnieje jeszcze jeden rodzaj raportu, który różni się nieco od innych, a jest dość często używany: etykiety adresowe. W następnej części tego rozdziału omówimy ten typ raportów i jego cechy charakterystyczne. Tworzenie prostych etykiet adresowych Mimo iż być może jeszcze nigdy nie miałeś potrzeby tworzenia etykiet adresowych, ta sama technika może być wykorzystana do tworzenia innych rzeczy, na przykład plakietek z nazwiskami, etykiet na dokumentację techniczną, identyfikatorów wyposażenia itp. Access posiada Kreatora etykiet, który potrafi drukować etykiety w setkach różnych formatów. Formaty te mogą być wybierane podczas działania kreatora lub też później. Aby utworzyć etykiety, utwórz nowy raport i wybierz Kreator etykiet z okna Nowy raport. Jako źródło danych wybierz tabelę Customers. Kliknięcie OK uruchamia kreator etykiet. 45. Wybieranie formatu etykiet nie jest trudne. Przedstawione na rysunku 10.12 okno dialogowe zawiera dokładne wymiary najczęściej spotykanych etykiet i według nich automatycznie formatuje raport. Musisz wybrać jednostki miary (angielskie lub metryczne) oraz typ etykiety (najczęściej spotykany Podawany arkuszami albo Ciągły). Każdy z dokonywanych przez Ciebie wyborów zmienia liczbę dostępnych produktów. Możesz filtrować etykiety według ich producentów. Domyślnym ustawieniem jest Avery, gdyż etykiety tego producenta są najczęściej używane i wielu innych producentów dostosowuje się do ich rozmiarów oraz używa na swoich produktach tych samych numerów produktów. Rysunek 10.12. Wybierz typ etykiety odpowiadający etykietom, na których będziesz drukował Jeśli znajdziesz się w sytuacji, w której nie będzie etykiety odpowiadającej Twoim potrzebom, klikając przycisk Dostosuj, możesz utworzyć własny format etykiety. 46. Gdy znalazłeś etykietę odpowiadającą tym, których używasz, przejdź do następnego okna kreatora, aby wybrać rodzaj i wielkość czcionki. Ponieważ Windows umożliwia wybór dowolnego rodzaju i wielkości czcionki, może się zdarzyć, że wybierzesz czcionkę zbyt dużą dla etykiety. W oknie dialogowym zobaczysz jak etykieta będzie wyglądać w przypadku wybrania danego rodzaju i wielkości czcionki. Dzięki temu unikniesz przykrych niespodzianek przy drukowaniu etykiet. 47. Naciśnięcie przycisku Dalej spowoduje przejście do kolejnego okna dialogowego (rysunek 10.13), w którym będziesz mógł określić wygląd etykiety. Duży, pusty obszar po prawej stronie zawiera pola prototypu etykiety. Możesz przenosić do niego pola ze źródła danych, klikając dwukrotnie lub korzystając z przycisku >. Aby zacząć od nowej linii, musisz na końcu poprzedniej wcisnąć klawisz Enter. Po utworzeniu linii możesz umieścić jej elementy w osobnych liniach. Aby usunąć określony element z prototypu, zaznacz go wskaźnikiem myszy i naciśnij klawisz Delete. Wprowadzanie tekstu odbywa się w sposób standardowy: po prostu kliknij odpowiednie miejsce i pisz. Każda z czynności, którą wykonujesz na prototypie etykiety, ma wpływ na wszystkie etykiety. Rysunek 10.13. Wypełniony prototyp etykiety Przedstawiony na rysunku 10.13 prototyp etykiety umożliwi tworzenie etykiet zawierających u góry nazwę firmy, poniżej adres i nazwisko osoby, do której list będzie przeznaczony. Zwróć uwagę na przecinek i spację po {Miasto}. Znaki te umieszczone zostaną na każdej z etykiet. To samo dotyczy znajdującego się u dołu etykiety zwrotu „Do wiadomości”. 48. Przejście do następnego okna Kreatora etykiet umożliwia nam zmianę kolejności sortowania etykiet. Możesz je sortować według kilku pól (na przykład nazwisko, a potem imię) lub według jednego. Jeśli nie określisz kolejności sortowania, etykiety zostaną ułożone w takiej kolejności, w jakiej znajdują się w źródle rekordów. Podczas tworzenia dużej ilości etykiet adresowych możesz je posortować według kodu pocztowego (rysunek 10.14). Rysunek 10.14. Wybór sortowania po kodzie pocztowym 49. W ostatnim oknie dialogowym podajmy nazwę raportu. Ponieważ są to etykiety adresowe klientów, wpisujemy „Korespondencja z klientami”. Możesz również zdecydować, czy otworzyć raport w widoku Projekt, czy też Podgląd wydruku. Wybór opcji Chcę zmienić projekt etykiety pozwoli zobaczyć, że etykieta to zwykły raport, z odpowiednio ustawionymi właściwościami. Wynikiem działania kreatora jest mały raport, zawierający pola odpowiadające każdej z widocznych w prototypie linii. Zauważ, że kreator połączył oddzielne pola Miasto, Region oraz Kod pocztowy i utworzył z nich jedną linię. Zauważ również, że kreator otoczył pola funkcją Trim(). Dzięki temu przed i za polami nie występują spacje, które mogłyby wpłynąć na wyrównanie etykiet. Gdybyś tworzył te etykiety ręcznie, musiałbyś sam utworzyć konkatenację i odwoływać się do funkcji Trim w każdym formancie. Raport swoimi rozmiarami idealnie odpowiada wybranemu typowi etykiety. Wysokość i szerokość raportu sprawiają, że dane będą drukowane kolumna po kolumnie i strona po stronie. Właściwość Trzymaj grupę razem jest ustawiona na Na kolumnę. To, w połączeniu z innymi ustawieniami właściwości, sprawia, że raport jest szeroki na dwie kolumny i w każdej z nich mieści cztery etykiety. Jeśli już wcześniej miałeś do czynienia z etykietami, prawdopodobnie nasuwa Ci się kilka pytań. Co jeśli adres zajmuje więcej niż jedną linię? Jak przesunąć region i kod pocztowy, gdy nazwa miasta jest bardzo długa lub bardzo krótka? Właściwości Można powiększać i Można zmniejszać dla tych formantów ustawione są na Tak, więc będą one automatycznie dostosowywać się do zmiany warunków. Dzięki temu nie zachodzi potrzeba tworzenia osobnych procedur warunkowych, aby brać takie możliwości pod uwagę. Publikowanie raportu Access jest doskonałym, lecz nie jedynym narzędziem do zarządzania danymi i tworzenia raportów. Często zdarza się, że bardzo niewygodnym jest instalowanie u każdego z użytkowników Accessa, by mogli przeglądać i drukować dane z raportów, a dostarczenie wydrukowanego raportu do więcej niż kilku użytkowników to męczące i czasochłonne zadanie. Co więcej, niektórzy użytkownicy mogą chcieć obrabiać dane w raporcie po jego otrzymaniu. Raport może zawierać dokładnie to, czego życzą sobie użytkownicy, jednakże forma i układ, w jakim są prezentowane, mogą sprawić, że dane te będą dla nich prawie bezużyteczne. Czasami dane z raportu Accessa muszą być opublikowane w inny, bardziej twórczy i dostosowany do potrzeb użytkowników sposób niż zwykły raport. Metody publikowania raportów W tej części omówimy sposoby, na jakie można rozpowszechniać raporty Accessa poprzez programy Word, Excel i pocztę elektroniczną. Istnieje kilka różnych formatów, które mogą pomóc dopasować raporty do potrzeb użytkowników. Nowym sposobem na rozpowszechnianie raportów w sieci są strony dostępu do danych. Ponieważ są to jednak osobne obiekty, omówione zostały w rozdziale 26., „Użycie stron dostępu do danych”. Pierwszą z decyzji, jakie musisz podjąć przed opublikowaniem danych jest to, czy użytkownicy wymagają sformatowanej, zawierającej podsumowania wersji danych, czy może zależy im na nieprzetworzonych danych. Jeśli mamy do czynienia z drugim przypadkiem i użytkowników nie interesuje wygląd, obliczenia, grupowania itp., najlepiej będzie przekazać im dane, eksportując kwerendę lub tabelę, niż wysyłać raport. Sposób postępowania przy eksportowaniu kwerendy lub tabeli jest bardzo podobny do eksportowania raportu, jednak w przypadku zestawów rekordów istnieje kilka innych opcji do wyboru. Najważniejszymi rzeczami, o których należy pamiętać przy publikowaniu raportu, jest to, że opublikowany raport nie będzie uwzględniał zmian dokonanych w źródle rekordów oraz to, że użytkownicy nie będą mieli możliwości modyfikowania informacji podsumowujących w celu poznania szczegółów. Jeśli akceptujesz te ograniczenia, reszta tego rozdziału będzie odpowiadać Twoim potrzebom. Użycie wbudowanych metod Accessa do eksportowania raportów Access posiada siedem opcji umożliwiających eksportowanie lub publikowanie raportów (rysunek 10.15). Każda z tych opcji to inny format pliku, do którego zapisywane są informacje o raporcie i jego układzie. Zostały one opisane w poniższej tabeli. Tabela 10.3. Opcje eksportowania raportów w Accessie Format pliku Rozszerzenie pliku Opis Access *.mdb, *.adp, *.mdw Eksportuje cały raport do innej bazy danych w Accessie Excel *.xls Zapisuje rezultaty raportu w arkuszu danych Excela (wersja 5 i 7) Excel *.xls Zapisuje rezultaty raportu w arkuszu danych Excela (wersja 97 i 2000) HTML *.html, *.htm Tworzy wersję raportu w języku HTML. Każda ze stron raportu to osobny plik HTML, indeksowany według numerów stron (na przykład SprzedażWedługKategorii, SprzedażWedługKategorii2...) Do poruszania się między stronami służą automatycznie tworzone hiperłącza Text *.txt, *.csv, *.tab, *.asc Powszechnie akceptowany format pliku, rozpoznawany przez prawie każdą aplikację. Wszelkie informacje o sposobie formatowania zostaną utracone Rich Text Format *.rtf Format ten zatrzymuje podstawowe informacje o sposobie formatowania. Rozpoznawany jest przez większość edytorów tekstu SnapShot Format *snp Format charakterystyczny dla Accessa. Umożliwia on przesłanie raportu do osób nie posiadających Accessa. Wymaga przeglądarki Microsoft Snapshot Viewer Rysunek 10.15. Okno dialogowe Eksportuj Aby wybrać jeden z omówionych formatów, wystarczy zaznaczyć raport i z menu plik wybrać Eksportuj. Wyświetlone zostanie okno dialogowe, w którym możesz wybrać lokalizację, nazwę i format pliku. Użycie łączy pakietu Office do publikowania raportów Innym sposobem na publikowanie raportów są łącza pakietu Office. Przeglądając raport w widoku Podgląd wydruku, możesz nacisnąć znajdujący się na pasku narzędzi przycisk Łącza Office, a wybrany raport zostanie wysłany do Worda lub Excela. Wówczas możesz zapisać go w dowolnym miejscu. Problemy związane z publikacją Gdy używasz formatów Excel i Text jako wyjściowych, istnieje ryzyko utraty części informacji o sposobach formatowania raportu, tak więc przed udostępnieniem go użytkownikom sprawdź, czy nadaje się do użytku. Użycie poczty elektronicznej do publikowania raportów Wysyłanie raportów pocztą elektroniczną może się odbywać z poziomu Accessa poprzez zgodny z MAPI system pocztowy (na przykład Microsoft Exchange). Gdy otwarłeś raport w widoku Podgląd wydruku lub po zaznaczeniu go w oknie bazy danych z menu Plik wybierz Wyślij do. Możesz wysłać raport jako załącznik w formatach HTML, Excel, DOS Text, RTF lub SnapShot. Aby przeglądać raport w formacie SnapShot, należy posiadać przeglądarkę SnapShot Viewer. Umożliwia ona przeglądanie raportu w sposób przypominający widok Podgląd wydruku Accessa. Przydaje się to w szczególności w przypadku przesyłania raportów pocztą elektroniczną, gdyż umożliwia przeglądanie załączników bez zniekształceń. Więcej informacji o pisaniu kodu umożliwiającego przesyłanie pocztą elektroniczną raportów i innych obiektów Accessa znajdziesz w rozdziale 18., „Użycie automatyzacji ActiveX”. Gdy eksportujesz lub przesyłasz raport oparty na kwerendzie parametrycznej, raport może nie funkcjonować poprawnie. Zastanów się, czy nie będzie lepiej oprzeć eksportowaną wersję na statycznej tabeli z tym samym ustawieniem parametrów. Modyfikowanie raportu podczas jego działania Ponieważ raport jest takim samym obiektem jak wszystkie inne obiekty Accessa, istnieje możliwość napisania kodu, który będzie wpływał na jego właściwości i w określony sposób reagował na zdarzenia. Pozostała część tego rozdziału będzie poświęcona obiektowi Raport oraz jego właściwościom i zdarzeniom. Ponieważ formularze i raporty są do siebie podobne, zajmiemy się jedynie cechami charakterystycznymi raportów lub tym aspektom ich działania, które są dla nich wyjątkowe. Zdarzenia dla raportów i sekcji można podzielić na związane z procesem projektowania oraz związane z funkcjonowaniem raportu. Podział ten jest bardzo ważny w przypadku rozwiązywania poważnych problemów związanych z raportami. Właściwości związane z procesem projektowania mogą być ustawiane jedynie w widoku Projekt. Gdy raport już działa, nie można tych ustawień modyfikować. Właściwości związane z funkcjonowaniem raportu mogą być modyfikowane za pomocą kodu, gdy raport jest otwierany, formatowany czy drukowany, dając Ci dynamiczną kontrolę nad jego wyglądem i zawartością. Aby modyfikować raport podczas jego funkcjonowania (a także w procesie projektowania) konieczne jest dogłębne zrozumienie jego właściwości, zdarzeń i obiektów. Przejdźmy do przeglądu tych elementów. Filtrowanie i sortowanie Właściwości te działają prawie identycznie jak ich odpowiedniki z formularzy. Korzystając z właściwości Filtr, możesz ograniczyć zawartość raportu. Filtrowanie działa tylko wówczas, gdy właściwość Filtr włączony ustawiona jest na Tak. Aby zobaczyć jak działa filtrowanie w formularzu, postępuj w następujący sposób: 50. Otwórz raport Katalog w widoku Projekt. 51. Zmień właściwość Filtr włączony na Tak. 52. We właściwości Filtr wprowadź następujące wyrażenie: [NazwaKategorii] = "Napoje" 53. Przejdź do widoku Podgląd wydruku. Wyświetlone powinny zostać jedynie napoje. 54. Powróć do widoku Projekt i ustaw właściwość Filtr włączony na Nie. 55. Przejdź do widoku Podgląd wydruku. Wyświetlone zostaną wszystkie kategorie. Aby użyć tych właściwości w kodzie, mógłbyś utworzyć następujące procedury: Reports![Katalog].FilterOn=True lub Reports![Katalog].Filter=[NazwaKategorii]= "Napoje" Trzymaj grupę razem Przy tworzeniu raportów wielokolumnowych może zaistnieć konieczność zachowania grup w kolumnie lub na stronie w całości. Oto dwie dostępne opcje: ? Na kolumnę – gdy właściwość ta jest użyta łącznie z umieszczoną w oknie dialogowym Sortowanie i grupowanie właściwością Trzymaj razem, Access spróbuje zmieścić całą grupę w tej samej kolumnie. ? Na stronę – gdy właściwość ta jest użyta łącznie z umieszczoną w oknie dialogowym Sortowanie i grupowanie właściwością Trzymaj razem, Access spróbuje zmieścić całą grupę na tej samej stronie. HasData Gdy raport główny wykonuje obliczenia na podraporcie, w którym nie ma danych, wyrażenie może wyświetlić komunikat o błędzie. Do określenia, czy istnieją dane dla raportu lub formantu, możesz użyć właściwości HasData. Właściwość ta zwraca trzy wartości: Tabela 10.4. Wartości właściwości HasData Wartość Opis Raport niezwiązany Raport nie posiada źródła rekordów Raport związany, bez rekordów Raport posiada źródło rekordów, lecz jest ono puste -1 – Raport związany, zawiera rekordy Raport posiada źródło rekordów zawierające co najmniej jeden rekord Do sprawdzenia, czy obliczenia powinny być wykonywane, wystarczy prosta formuła: ="Category has " & if ([CategorySubRpt].[Report].[HasData] = -1, _ [CategorySubRpt].[Report]![CatCount],0) & " products." Zdarzenia raportu (podczas jego działania) Poniższe zdarzenia to niektóre ze zdarzeń uruchamianych podczas działania raportu. Oznacza to, że uruchamiane są, gdy raport jest drukowany, zaznaczany itd. Są to zdarzenia, których będziesz używał do kontroli zachowań związanych z interakcją z użytkownikami lub danymi raportu. Przy otwarciu Przy otwarciu jest to pierwsze zdarzenie po uruchomieniu raportu. Występuje przed otwarciem podległej kwerendy. Jest w takim razie dobrym miejscem na dokonanie programowych zmian w kwerendzie lub na podanie jej określonych parametrów. Kod napisany w zdarzeniu Przy otwarciu zostanie wykonany, zanim w raporcie stanie się cokolwiek innego. Po zakończeniu tego zdarzenia raport podejmie działania konieczne do załadowania danych. Przy aktywowaniu, przy dezaktywowaniu Zdarzenia te uruchamiane są, gdy raport staje się aktywnym oknem (w przypadku Przy dezaktywowaniu przestaje nim być) lub gdy rozpoczyna się drukowanie raportu. Przy braku danych Dawniej, gdy po otwarciu raport nie zawierał żadnych rekordów lub jego filtr nie zwrócił żadnych wierszy, Access wyświetlał komunikat o błędzie. Na szczęście problem ten został rozwiązany i teraz formanty związane z pustym źródłem rekordów są po prostu puste. Jednakże zdarzenie Przy braku danych będzie w takim przypadku uruchamiane. Może być użyte do grzecznego poinformowania użytkowników o braku rekordów i anulowania raportu. Gdyby raport miał wyświetlać zamówienia według klientów, kod na wydruku 10.3 anuluje raport, gdyby dany klient nie posiadał żadnych zamówień. Wydruk 10.3. Anulowanie raportu przy braku danych Private Sub Report_NoData(Cancel As Integer) ' Ostrzeż użytkownika MsgBox "Ten klient nie składał zamówień" ' Anuluj otwieranie raportu Cancel = True End Sub Przy błędzie Jeśli tabela, na której poparty jest raport, otwarta jest przez innego użytkownika z wyłącznością lub po prostu nie istnieje, aparat Jet stwierdzi błąd i uruchomi zdarzenie raportu Przy błędzie. Zdarzenie to połączone jest z procedurą AccessError obiektu Application, więc do rozwiązania tego problemu nie możesz użyć Err.Description. Najlepszym sposobem na radzenie sobie z błędami w raportach jest użycie modułu klasy raportu. Przy stronie Zdarzenie to umożliwia dokonywanie zmian w raporcie w ostatnim momencie, tuż przed jego wydrukowaniem lub przeglądaniem w widoku Podgląd wydruku. Niektóre zmiany (związane na przykład z obramowaniem stron lub obliczaniem niestandardowych podsumowań) łatwiej jest wykonywać po sformatowaniu raportu, jednak przed jego wydrukowaniem. Metoda Line spowoduje narysowanie linii wokół raportu, zanim zostanie on wydrukowany: Me.Line (0, 0) – (Me.ScaleWidth, MeScaleHeight), , B Przy zamknięciu Zdarzenie to występuje zaraz po zamknięciu raportu, jednak przed jego dezaktywacją. Możesz chcieć zamknąć wraz z raportem formularz służący do wprowadzania parametru lub zmienić pozycję innych okien. Zadania te, jak i inne porządkujące czynności, mogą być wpisane w zdarzenie Przy zamknięciu. Właściwość Sekcja Raport w Accessie może zawierać maksymalnie 25 sekcji: Nagłówek/Stopka raportu, Nagłówek/Stopka strony, Szczegóły oraz maksymalnie dziesięć Nagłówków/Stopek grup. Właściwość Sekcja zawiera tablicę opisującą wszystkie sekcje raportu. Do sekcji można tworzyć odniesienia za pomocą numerów ich indeksów w tablicy (a także stałych Accessa). Sekcje różnią się od innych właściwości Accessa tym, że nie zwracają własnej wartości, lecz odniesienie do sekcji. Aby w raporcie widoczny był nagłówek raportu, należy użyć następującego kodu: Reports![Produkty wg kategorii].Section(1).visible=true lub Reports![Produkty wg kategorii].Section(acHeader).visible=true Nazwa Jak wynika z tabeli 10.5, sekcje raportu posiadają również właściwość Nazwa, której można użyć do tworzenia odniesień. Aby poprawić przejrzystość raportu, możesz w dowolnym momencie zmienić nazwę sekcji i tworzyć odniesienia, używając nowo przyznanej nazwy. Tabela 10.5. Sekcje wraz z ich indeksami oraz stałymi Sekcja Indeks Nazwa/Stała Szczegóły 0 acDetail Nagłówek 1 acHeader Stopka 2 acFooter Nagłówek Strony 3 acPageHeader Stopka Strony 4 acPageFooter Nagłówek Grupy – poziom 1 5 Nazwa pola grupy Stopka Grupy – poziom 1 6 Nazwa pola grupy Nagłówek Grupy – poziom 2 7 Nazwa pola grupy Stopka Grupy – poziom 2 8 Nazwa pola grupy Nagłówek Grupy – poziom 3 ...itd. 9...itd. Nazwa pola grupy Wysokość Właściwość ta umożliwia określenie wysokości sekcji. Widoczny Właściwość ta sprawia, że sekcja jest widoczna lub nie. Przyjmuje wartości Tak i Nie. Właściwości sekcji związane z procesem projektowania Sekcje posiadają grupę właściwości, które mogą być odczytywane i zmieniane jedynie w procesie projektowania. Ważnym jest odróżnianie ich od innych właściwości, które dostępne są podczas pracy raportu, po ich ustawieniu. Można powiększać, można zmniejszać Są to dwie, różne właściwości, umożliwiające określenie, czy sekcja może zmieniać swój rozmiar, w celu reagowania na zmiany wielkości formantów. Jeśli w sekcji z właściwością Można powiększać ustawioną na Tak umieścisz formant zawierający więcej rekordów, dzięki właśnie tej właściwości dane zostaną wyświetlone poprawnie. Formanty mogą zmieniać swoje rozmiary inaczej niż przewidywałeś, jeśli stykają się z innymi formantami. Ponieważ właściwość ta dotyczy jedynie wysokości sekcji (nie wpływa na szerokość czy pozycję), pamiętaj, by sprawdzić, czy formanty na pewno na siębie nie nachodzą. Duże formanty (np. obiekty OLE) mogą utrudniać zmniejszanie innych formantów w sekcji, ponieważ powiększanie i zmniejszanie odbywa się linia po linii. W celu zmniejszenia sekcji należy w formancie OLE umieścić pusty obrazek. Rozmiar nagłówków i stopek stron nie może się zmieniać, więc umieszczone w tych sekcjach formanty muszą odpowiadać ich rozmiarom. Nowy wiersz lub kolumna Przy tworzeniu raportów kolumnowych ustawienia właściwości Nowy wiersz lub kolumna dają Ci dużą kontrolę nad wyglądem raportu. Ustawienia te opisane są w tabeli 10.6. Tabela 10.6. Ustawienia właściwości Nowy wiersz lub kolumna Nazwa Wartość Opis Nie 0 Kontrolę nad układem wierszy i kolumn sprawują wartości z okna dialogowego Ustawienia strony. Są to wartości domyślne. Przed sekcją 1 Każda sekcja zaczyna się od nowego wiersza lub kolumny. Jeśli wystarczy miejsca, nowa sekcja może współdzielić kolumnę lub wiersz. Po sekcji 2 Po wydrukowaniu sekcji tworzony jest nowy wiersz lub kolumna. Przed i po 3 Każda sekcja zaczyna się od nowego wiersza lub kolumny. Powtórz sekcję Użytkownicy i programiści aplikacji Accessa często skarżyli się, że zdarza się, iż gdy grupa przenoszona jest na nową stronę, jej nagłówek pozostaje na stronie poprzedniej. Ustawienie właściwości Powtórz sekcję na Tak spowoduje, że nagłówek bieżącej grupy zostanie umieszczony na nowej stronie. Właściwości sekcji (podczas działania raportu) Do opisanych poniżej właściwości programista ma dostęp po uruchomieniu raportu. Może dzięki nim modyfikować zachowanie i wygląd raportów, reagując w ten sposób na zachowanie danych i inne warunki. Wymuszaj nową stronę Właściwość ta jest krokiem naprzód w nadzorowaniu podziału strony. Może być ona użyta podczas drukowania raportu. Ustawiając tę właściwość (opartą na danych ze źródła rekordów), możesz kontrolować podział strony w odniesieniu do układu sekcji. Tabela 10.7 zawiera ustawienia tej właściwości. Tabela 10.7. Ustawienia właściwości Wymuszaj nową stronę Nazwa Wartość Opis Nie 0 Ustawienie domyślne. Bieżąca sekcja drukowana jest na bieżącej stronie Tak 1 Nowa sekcja zaczyna się od nowej strony Trzymaj razem Poprawne działanie tej właściwości zależy od spełnienia kilku warunków. Gdy ustawiona jest ona na Tak, Access będzie usiłował wydrukować całą sekcję na jednej stronie. Jeśli to nie będzie możliwe, spróbuje on umieścić sekcję na nowej stronie. Jeśli to również się nie powiedzie, grupa zostanie umieszczona na więcej niż jednej stronie. W przeciwieństwie do analogicznej właściwości dla grupy, w przypadku sekcji Trzymaj razem dotyczy tylko jednej, konkretnej sekcji. PrzenieśUkład, NastępnyRekord i DrukujSekcję Właściwości te umożliwiają kontrolowanie tego, co i w jaki sposób jest drukowane. ? PrzenieśUkład – ustawienie True (Prawda) umożliwi Accessowi przejście do drukowania następnego elementu strony. Ustawienie False (Fałsz) sprawia, że raport nie przechodzi do drukowania następnego elementu strony. ? NastępnyRekord – gdy właściwość ta ustawiona jest na True, raport przejdzie do następnego rekordu ze źródła rekordów (co nie nastąpi w przypadku ustawienia False). ? DrukujSekcję – ustawienie True – sekcja będzie drukowana, False – nie. Właściwości te nadzorują sposób, w jaki raport odczytuje dane ze źródła, przygotowuje stronę do wydruku oraz drukuje daną sekcję. Użyte razem, właściwości te mogą powtarzać dane, tworzyć puste wiersze, drukować różne wiersze w tej samej linii lub pomijać określone wiersze. Tabela 10.8 zawiera szczegóły użycia tych właściwości oraz ich rezultaty. Tabela 10.8. Sekcje wraz z ich indeksami oraz stałymi Oczekiwany rezultat MoveLayout NextRecord PrintSection Drukuj każdy wiersz, jeden po drugim True True True Zostaw puste miejsce True True False Powtórz wiersz True False True Zostaw puste miejsce, pozostań przy tym samym wierszu danych True False False Drukuj różne wiersze w tej samej linii False True True Pozostań w tej samej linii, lecz opuść wiersz danych False True False LiczbaFormatowań Właściwość ta zwiększana jest za każdym razem, gdy strona jest formatowana do druku. Sekcja może być formatowana więcej niż jeden raz. Może się to zdarzyć, gdy sekcja powinna mieścić się na jednej stronie, jednak się nie mieści. W takim przypadku, Access sformatuje ją raz na pierwotnej stronie i drugi raz na nowej stronie, ustawiając wartość LiczbaFormatowań na 2. Ma to znaczenie w sytuacji, gdy wykonujesz obliczenia w zdarzeniu Przy formatowaniu, gdyż obliczenia te mogą wystąpić więcej niż raz, jeśli nie są kontrolowane przez tę właściwość. LiczbaDrukowań Właściwość ta zwiększana jest za każdym razem, gdy sekcja jest drukowana. Sekcja może być drukowana więcej niż jeden raz. Może się to zdarzyć, gdy sekcja powinna mieścić się na jednej stronie, jednak się nie mieści. W takim przypadku, Access spróbuje wydrukować ją raz na pierwotnej stronie i drugi raz na nowej stronie, ustawiając wartość LiczbaDrukowań na 2. Ma to znaczenie w sytuacji, gdy wykonujesz obliczenia w zdarzeniu Przy wydruku, gdyż obliczenia te mogą wystąpić więcej niż raz, jeśli nie są kontrolowane przez tę właściwość. ByłKontynuowany, BędzieKontynuowany Są to właściwości o ograniczonym zastosowaniu. Ustawiane są, gdy sekcja przeszła lub przejdzie na nową stronę. Ich zastosowanie jest ograniczone, gdyż osoba pisząca raport w Accessie nie jest w stanie stwierdzić, czy nakładanie się spowodowane jest przez dane czy przez puste miejsca. Dlatego też, właściwość BędzieKontynuowany jest zazwyczaj ustawiona na True dla każdej strony raportu. Wydaje się, że jedynym sposobem na pokonanie tego braku „inteligencji” programu jest upewnienie się, iż wysokość sekcji dzieli się równomiernie na możliwą do zadrukowania przestrzeń na stronie. Właściwość ByłKontynuowany ustawiana jest w zdarzeniu Przy formatowaniu. Ustawienie True występuje, gdy kontynuowana była sekcja z poprzedniej strony. Jednakże trudno jest znaleźć zastosowanie dla tej właściwości, gdyż jej wartość jest ustawiana zbyt późno, by wykorzystać ją w raporcie. Programowe tworzenie raportów Prawdopodobnie największym wyzwaniem dla programisty jest stworzenie raportu dla danych, które ulegają ciągłym zmianom. Wyobraźmy sobie okresowy raport o sprzedaży produktów według regionów. Załóżmy też, że musi mieć on postać tabeli. Jeśli raport oparty jest na kwerendzie krzyżowej, nazwy kolumn użyte jako ich nagłówki będą się prawdopodobnie zmieniać co miesiąc. Będzie to problem dla związanych formantów w raporcie. Jednym z możliwych rozwiązań jest programowe tworzenie raportu za każdym razem, gdy jest to konieczne. Można tego dokonać przy użyciu modułu VBA. Przedstawiony moduł VBA mógłby, z pewnymi poprawkami, zostać umieszczony w zdarzeniu raportu Przy otwarciu i po prostu modyfikować istniejący raport. By jednak dobrze zrozumieć tworzenie raportu z samego kodu, musi to być osobny moduł. Dla zachowania prostoty, w naszym przykładzie używamy obiektów DAO. Ponieważ obiekty ADO nie umożliwiają tworzenia kwerend krzyżowych, użycie DAO oszczędzi nam konieczności tworzenia tymczasowej tabeli, umożliwi wykorzystanie znanej już większości czytelników techniki uzyskiwania dostępu do danych oraz skoncentrowanie się na kwestiach związanych z raportem. Tworzenie źródła rekordów Pierwszym krokiem jest stworzenie źródła rekordów. Przedstawiona w listingu 10.4 funkcja o nazwie MakeCrosstabQuery posiada dwa argumenty danych: datFrom i datTo. Określają one okres, jakiego raport dotyczy. Jeśli definicja kwerendy nie istnieje, zostanie utworzona przez funkcję. W przeciwnym wypadku po prostu zaktualizowana zostanie właściwość SQL definicji kwerendy. Do funkcji tej będziemy się odwoływać z funkcji tworzącej raport, jednakże mogłaby być wykorzystywana przez samą siebie do innych celów. Wydruk 10.4. Programowe tworzenie kwerendy krzyżowej Function MakeCrosstabQuery(datFrom As Date, datTo As Date) As Boolean ' Obsługa błędów w kodzie On Error Resume Next Dim db As Database Dim qrydef As querydef Dim strSQL As String Set db = CurrentDb ' Upewnij się, że znasz wszystkie obiekty w pojemniku, używając ' procedury Refresh (odśwież) db.QueryDefs.Refresh ' Pobierz kwerendę Set qrydef = db.QueryDefs("Ilość dostarczona według regionów") ' Jeśli kwerenda nie istnieje, utwórz obiekt. Jeśli obiekt nie ' istnieje, obiekt Err zwróci komunikat o błędzie 3265. If (3265 = Err) Then Set qrydef = db.CreateQueryDef( _ "Ilość dostarczona według regionów") ' Jako, że utworzyłeś nowy obiekt, odśwież pojemnik db.QueryDefs.Refresh ' Zanim przejdziesz dalej, wyzeruj obiekt Err Err = 0 End If ' Dla skrócenia procedury załóż, że daty są poprawne datFrom = CStr(datFrom) datTo = CStr(datTo) ' Utwórz procedurę SQL strSQL = strSQL & "TRANSFORM Sum([Order Details].Quantity) " strSQL = strSQL & "AS SumOfQuantity " strSQL = strSQL & "SELECT Products.ProductName " strSQL = strSQL & "FROM Products INNER JOIN " strSQL = strSQL & "(Orders INNER JOIN [Order Details] ON _ Orders.OrderID = " strSQL = strSQL & "[Order Details].OrderID) ON Products.ProductID _ = [Order Details].ProductID " strSQL = strSQL & "WHERE (((Orders.OrderDate) Between #" & datFrom _ & "# And #" & datTo & "#) AND " strSQL = strSQL & "((Orders.ShipRegion) Is Not Null)) " strSQL = strSQL & "GROUP BY Products.ProductName " strSQL = strSQL & "ORDER BY Orders.ShipRegion " strSQL = strSQL & "PIVOT Orders.ShipRegion; " ' Skoro obiekt został już utworzony, wystarczy zmienić ' procedurę SQL zmieniając właściwość SQL qrydef.SQL = strSQL If (Err) Then ' W tym miejscu przekaż błąd do twojego modułu zajmującego ' się ich poprawianiem Exit Function End If ' Zamknij obiekt Kwerenda qrydef.Close db.QueryDefs.Refresh End Function Po utworzeniu kwerendy możesz przejść do tworz,enia raportu. Funkcja PrepareCrosstabReport() zawiera dwa argumenty danych: datFrom i datTo. Zostaną one przekazane do funkcji MakeCrosstabQuery. Funkcja ta będzie również korzystać z ikony bazy danych, obiektu recordset (zestaw rekordów), bardzo ważnego obiektu Raport i kilku innych zmiennych, użytych jako liczniki. Tworzenie obiektu Raport Funkcja PrepareCrosstabReport() utworzy nową kwerendę, uruchomi ją, a następnie utworzy nowy obiekt Raport, który będzie zgodny z właściwościami nowej kwerendy. Po utworzeniu obiektu Raport funkcja przejdzie do umieszczenia w sekcjach raportu formantów oraz związaniu ich ze źródłem danych. Ponieważ Access numeruje formanty w kolejności ich tworzenia, sprawowanie kontroli nad tym, czy formanty następują po sobie w tej samej kolejności co etykiety, wydaje się być ułatwione. Aby to osiągnąć, funkcja tworzy etykiety i wiąże formanty w osobnych pętlach. Stopka raportu tworzona jest przy użyciu procedury RunCommand obiektu DoCmd, a następnie jej właściwość Widoczny (Visible) zmieniana jest na True. Osobna pętla tworzy i rozmieszcza formanty zawierające funkcję Suma(). Ustawiana jest wysokość sekcji Szczegóły (Detail), przydzielane jest źródło rekordów, by na końcu otworzyć raport. Wydruk 10.5. Tworzenie raportu przy użyciu kodu Public Function PrepareCrosstabReport(datFrom As Date, datTo As Date) As Boolean On Error GoTo PrepareCrosstabReport_Err Dim db As Database Dim DocName As String Dim rs As Recordset Dim rpt As Report Dim i As Integer Dim x As Integer Set db = CurrentDb() 'Wyzeruj kwerendę, by używać nowych danych i otwórz ją MakeCrosstabQuery datFrom, datTo Set rs = db.OpenRecordset("Ilość dostarczona według regionów") ' Utwórz obiekt Raport Set rpt = CreateReport("", "") rpt.Caption = " Ilość dostarczona według regionów Between " & _ datFrom & " and " & datTo ' Teraz musisz utworzyć formanty Dim ctlNew As Control ' Do wypełnienia jest dziewięć formantów, więc... If rs.Fields.Count - 1 > 9 Then x = 9 Else x = rs.Fields.Count - 1 End If ' Utwórz, rozmieść, zwiąż i sformatuj formanty For i = 0 To x Set ctlNew = CreateReportControl(rpt.Name, acTextBox, acDetail) With ctlNew .Height = 270 .Width = 1080 .Top = 0 .Left = (60 + .Width) * i rpt("text" & i).ControlSource = rs.Fields(i).Name End With Next For i = 0 To x Set ctlNew = CreateReportControl(rpt.Name, acLabel, acPageHeader) With ctlNew .Height = 270 .Width = 1080 .Top = 0 .Left = (60 + .Width) * i ' Indeksy przyznawane są bez twojego udziału, więc ' kontroluj je! rpt("label" & i + x + 1).Caption = rs.Fields(i).Name End With Next DoCmd.RunCommand acCmdReportHdrFtr rpt.Section(acFooter).Visible = True For i = 0 To x Set ctlNew = CreateReportControl(rpt.Name, acTextBox, acFooter) With ctlNew .Height = 270 .Width = 1080 .Top = 0 .Left = (60 + .Width) * i ' Indeksy przyznawane są bez twojego udziału, więc ' kontroluj je! If i = 0 Then rpt("text" & i + (2 * x) + 2).ControlSource = "='Suma'" Else rpt("text" & i + (2 * x) + 2).ControlSource = _ "=sum([" & rs.Fields(i).Name & "])" End If End With Next rpt.Section("detail").Height = 0 rpt.RecordSource = " Ilość dostarczona według regionów" DoCmd.OpenReport rpt.Name, acViewPreview 'Normalnie, to zostałoby wydrukowane PrepareCrosstabReport = True PrepareCrosstabReport_Exit: Set rpt = Nothing rs.Close Exit Function PrepareCrosstabReport_Err: PrepareCrosstabReport = False MsgBox Error$ Resume PrepareCrosstabReport_Exit End Function Mamy teraz raport oparty na kwerendzie krzyżowej, który jest dynamicznie tworzony za każdym razem, gdy tego zażądamy. Ponieważ raport korzysta z wybranego źródła rekordów, nie jest nigdy problemem zmiana nagłówka kolumny czy ilości regionów, których raport dotyczy (w ramach jego wewnętrznych ograniczeń). Tworzenie sekcji Sekcje również mogą być tworzone programowo, jednakże nie wszystkie sekcje tworzone są w ten sam sposób. Aby utworzyć nagłówki i stopki grup, Access posiada funkcję CreateGroupLevel. Ponieważ pięć standardowych sekcji (Nagłówek/Stopka raportu, Nagłówek/Stopka strony i Szczegóły) nie jest częścią schematu grupowania raportu, tworzone są w inny sposób. Funkcja CreategroupLevel posiada cztery argumenty: ? StrReport – ciąg identyfikujący raport, który chcesz modyfikować. ? StrExpr – wyrażenie poziomu grupy, zazwyczaj nazwa pola, rodzaj obiektu lub data. ? FHeader/FFooter – wartości logiczne, służące do tworzenia dodatkowego nagłówka lub stopki sekcji. Wartość True – sekcja jest tworzona, False – nie. createGroupLevel "_Kategorie i produkty" , "newGroupsection" , 1, 1 lub intSection=createGroupLevel ("_Kategorie i produkty" , "newGroupSection" , 1, 1) Aby utworzyć nagłówki i stopki raportu lub strony, skorzystaj z metody RunCommand obiektu DoCmd: DoCmd.RunCommand acCmdReportHdrFtr Wskazówki Większość aplikacji posiada co najmniej jeden raport, który przysparza wielu problemów. Aby umożliwić Ci radzenie sobie przynajmniej z częścią z nich, damy teraz kilka wskazówek związanych z raportami. Tworzenie grupowania dwutygodniowego Jeśli grupujesz dane na dany dzień i chcesz uzyskać grupowanie dwutygodniowe (na przykład podczas tworzenia listy płac), w oknie dialogowym Sortowanie i grupowanie ustaw właściwość Grupuj według na Interwał, a właściwość Przedział grupowania na 2. Ukryj powtarzające się dane Może zdarzyć się, że w prostym raporcie tabelarycznym informacja powtarza się w kolejnych wierszach. Aby tego uniknąć, ustaw właściwość Ukryj Duplikaty danego formantu na Tak. Umożliwi Ci to uzyskanie wyglądu przypominającego grupowanie, jednak bez użycia sekcji oraz drukowanie danych określających grupę i pierwszej linii szczegółów w tym samym wierszu. Alfabetyczne grupowanie danych W raporcie wyświetlającym listę klientów według pola NazwiskoKlienta możesz, wykonując poniższe kroki, alfabetycznie podzielić klientów na grupy: 56. W oknie dialogowym Sortowanie i grupowanie ustaw właściwość Grupuj według na Pierwsze znaki. 57. Właściwość Przedział grupowania ustaw na 1 ( rysunek 10.16). Jest to ważne, gdyż stąd właśnie Access wie, ilu znaków ma użyć, dzieląc klientów na grupy. W takim przypadku, będzie zwracał uwagę na pierwszą literę nazwiska klienta. Rysunek 10.16. Ustawienia grupowania 58. Ustaw źródło formantu z nazwiskiem klienta na: =Left([NazwiskoKlienta]], 1) Tworzenie numerowanych list Użycie właściwości Suma bieżąca w połączeniu ze źródłem formantu umożliwi raportowi numerowanie obiektów na liście. Na rysunku 10.17 znajduje się przykład raportu z ponumerowanymi obiektami. Numerowanie może zaczynać się od nowa dla każdej grupy lub być kontynuowane przez cały raport. Rysunek 10.17. Rezultat numerowania 59. Umieść w raporcie formant, który będzie zawierał numer pozycji. 60. Ustaw źródło formantu na =1. Będzie to początek schematu numerowania. 61. Ustaw właściwość Suma bieżąca formantu na Wszędzie lub W grupie. Tworzenie pustych linii co n znaków W rozdziale tym opisaliśmy, jak przy użyciu właściwości PrzenieśUkład, NastępnyRekord i DrukujSekcję tworzyć puste linie. Wydruk 10.6 jest przykładem takiego kodu. Można go umieścić w większości raportów. By zmienić częstotliwość tworzenia pustych linii, wystarczy zmodyfikować stałą intSkipLine. Wydruk 10.6. Tworzenie pustych linii co n znaków Option Compare Database Dim intCurrLine As Integer Const intSkipLine = 3 Private Sub Detail_Format(Cancel) As Integer, FormatCount As Integer) If intCurrLine Mod (intSkipLine + 1) = 0 Then Me.NextRecord = False Me.PrintSection = False End If intCurrLine = intCurrLine + 1 End Sub Private Sub Report_Open(Cancel As Integer) cLines = 0 End Sub Zerowanie numeru strony dla nowych grup Ponieważ właściwość Page (strona) sekcji jest zapisywana lub odczytywana podczas uruchamiania raportu, można ją zmieniać przy każdym formatowaniu nagłówka grupy. Właściwość ta nie powinna być mylona z właściwością Strony, która nie może być zapisywana podczas działania raportu. Poniższy kod zeruje liczbę stron. Przydaje się on, gdy grupy zajmują więcej niż jedną stronę. Sub GroupHeader_Format Page=1 End Sub Rysowanie pionowych linii Tworzenie w raporcie pionowych linii może być dokonane z pomocą zaledwie kilku linijek kodu. Aby rysować linie w zdarzeniu Przy formatowaniu, ustaw pozycje i wywołaj metodę Line. Używaną tutaj miarą są twipy (1,440 cala). Wydruk 10.7 zawiera przykład procedury rysującej linię. Wydruk 10.7. Rysowanie poziomych linii przy użyciu kodu Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer) Dim x1 As Single 'Pozycja pozioma przeliczona z cali na twipy x1 = 3 * 1440 ' Użyj procedury raportu Line, gdzie ' x1, y1 to współrzędne początkowe, a ' x2, y2 to współrzędne końcowe Me.Line (x1, 1) – (x1, 32000) End Sub Przesuwanie numerów parzystych i nieparzystych stron Jeśli zajdzie potrzeba umieszczenia numerów stron parzystych po prawej, a nieparzystych po lewej stronie, pomocna będzie poniższa funkcja. Możesz chcieć jej również użyć przy tworzeniu marginesu do oprawy. Wydruk 10.8 zawiera przykład takiej techniki. Wydruk 10.8. Zmiana pozycji numerów parzystych i nieparzystych stron Private Sub Detail_Print(Cancel As Integer, PrintCount As Integer) If (Me!txtpagenumber Mod 2 = 0) Then txtpagenumber.TextAlign = 3 'Lewy Else txtpagenumber.TextAlign = 1 'Prawy End If End Sub Identyfikacja użytkownika drukującego raport Jeśli Twoja baza danych Accessa jest zabezpieczona, możesz określić identyfikator użytkownika drukującego raport oraz użyć tego identyfikatora do uzyskania nazwiska tego użytkownika. Wpisz poniższe wyrażenie jako źródło niezwiązanego formantu: =ObecnyUżytkownik() lub =dlookup("TabelaUżytkowników" , "[Nazwisko]", "[IDUżytkownika]= " & ObecnyUżytkownik() & ") Wyrównanie stron do oprawy Gdy strony mają być oprawione jak książka, musi być na nich miejsce na umieszczenie oprawy. Oznacza to, iż zawartość stron nieparzystych musi być przesunięta w prawo, a parzystych w lewo. Czynność taką wykonuje kod z wydruku 10.9. Wydruk 10.9. Wyrównywanie stron do oprawy Private Sub PageFooterSection_Format(Cancel As Integer, _ FormatCount As Integer) Dim ctl As Control If (Me.Page Mod 2 = 0) 'Strona jest parzysta For Each ctl In Me.Controls .Left = .Left + 1440 'przesuwa wszystko o jeden cal w lewo Next Else 'strona jest nieparzysta For Each ctl In Me.Controls .Left = .Left – 1440 'przesuwa wszystko o jeden cal w prawo Next End If End Sub Obliczanie podsumowań strony Access wyświetli komunikat o błędzie, jeśli będziesz próbował umieścić funkcję podsumowującą (np. Suma()) w formancie znajdującym się w nagłówku lub stopce strony. Ponieważ często pojawia się konieczność podsumowania strony, jest to dość niewygodne. Z pomocą prostego kodu można wykonać obliczenia podsumowujące wartości na stronie, a następnie wyświetlić je poprzez niezwiązany formant w stopce strony. Aby skorzystać z kodu użytego w przykładzie, konieczne jest wykonanie następujących czynności: 62. W oparciu o tabelę Faktury utwórz prosty raport. W części Szczegóły umieść pola NazwaOdbiorcy i CenaJednostkowa. 63. W części Szczegóły umieść ponownie pole CenaJednostkowa i zmień jego nazwę na SumaBieżąca. Ustaw właściwość Widoczny na Nie i Suma bieżąca na Wszędzie. 64. W stopce strony umieść niezwiązane pole tekstowe i nazwij je txtPageSubtot. 65. Kod z listingu 10.10 wprowadź do zdarzenia stopki strony Przy wydruku. Wydruk 10.10. Obliczanie podsumowania strony Option Compare Database Dim x As Double Private Sub PageFooterSection_Print(Cancel As Integer, _ PrintCount As Integer) txtpagesubtot = RunningSum – x x = RunningSum End Sub 'Teraz raport będzie zawierał podsumowania stron Precyzyjne przesuwanie formantów Aby zminimalizować ryzyko przesunięcia formantów, do ich zaznaczania możesz używać następujących technik: ? Kliknij linijkę, by zaznaczyć formanty znajdujące się w określonym miejscu. ? Kliknij tło raportu i przeciągnij zaznaczenie na odpowiednie formanty bez poruszania ich. ? Do przechodzenia między formantami używaj klawisza Tab. ? Kombinacja klawisza Ctrl i strzałek umożliwia precyzyjne przesuwanie formantu oraz przemieszczanie formantów między sekcjami. Kombinacja klawisza Shift i strzałek umożliwia zmianę rozmiaru formantów bez przesuwania ich. Część IV Tajniki VBA W tej części: ? Tworzenie obiektów przy użyciu modułów klasowych. ? Usuwanie błędów w aplikacjach Accessa. ? Profesjonalna obsługa błędów. ? Optymalizacja aplikacji. Rozdział 11. Tworzenie obiektów przy użyciu modułów klas W tym rozdziale: ? Korzyści z używania obiektów. ? Przegląd obiektów, własności i metod. ? Tworzenie klas. ? Tworzenie właściwości. ? Tworzenie metod. ? Tworzenie zdarzeń. ? Użycie obiektów. ? Tworzenie kopii obiektów. ? Przegląd innych obiektów. ? Implementacja obiektu do obsługi błędów. ? Użycie obiektów w połączeniu ze zbiorami VBA. Tworzenie obiektów jest jednym z najskuteczniejszych sposobów na pisanie i obsługę aplikacji. Zanim przejdziemy do omówienia korzyści płynących z użycia obiektów, zdefiniujmy podstawowe pojęcia. Obiekty to rzeczy. Samochody, budynki i komputery to różne typy obiektów. W języku programistów słowo obiekt oznacza jedną, określoną rzecz, na przykład formularz lub formant. Z pewnością już spotkałeś się z tego typu wbudowanymi obiektami. W trakcie swojej ewolucji Microsoft Access stał się programem zorientowanym obiektowo, umożliwiającym tworzenie własnych obiektów i metod dla tych obiektów. Takie obiekty to na przykład: obiekt klient, obiekt faktura, obiekt użytkownik, obiekt łącze da- nych czy obiekt dźwięk. Na dołączonej do książki płycie CD znajdziesz wiele stworzonych przez nas obiektów, które będziesz mógł wykorzystywać do własnych potrzeb („Tworzenie obiektów z modułów klas.mdb” – rysunek 11.1). Rysunek 11.1. Przykłady obiektów własnych, znajdujące się na dołączonej płycie CD-ROM Obiekty tworzone są przy użyciu modułów klasowych. Moduł klasowy to odrębna, przenośna, zaprojektowana w określonym celu jednostka kodu. Klasa określa właściwości i metody każdego z obiektów klasy. Programiści często mieszają pojęcia klasa i obiekt. Klasa to opis lub szablon właściwości i metod obiektu. Gdy programista chce użyć kodu w module klasy, tworzony jest egzemplarz klasy. Ten egzemplarz to obiekt. Stąd też określenie „tworzenie egzemplarza obiektu” jest niepoprawne. Obiekt sam w sobie jest egzemplarzem! Pojedynczy obiekt definiowany jest jako egzemplarz klasy. Z jednej klasy można utworzyć wiele obiektów, z których każdy będzie miał inne właściwości. Rozdział ten poświęcony jest tworzeniu obiektów przy użyciu modułów klasowych. Pamiętaj, że moduły formularza są modułami klasowymi. W taki sam sposób, jak dodajesz właściwości i metody do własnych obiektów, możesz też dodawać właściwości i metody do formularzy. Korzyści z używania obiektów Z tworzenia i używania obiektów płynie wiele korzyści, w tym: ukrywanie złożonego zestawu funkcji kodu, użycie IntelliSense, prostsze tworzenie i utrzymanie kodu oraz wiele innych. Ukrywanie złożoności Ukrywanie złożoności to jedna z korzyści płynących z używania obiektów. Doświadczony programista może tworzyć złożone procedury, na przykład procedury Windows API, kod dostępu do danych, procedury ciągów i inne. Mniej doświadczeni programiści mogą korzystać z obiektów, odwołując się do ich właściwości i metod bez konieczności zrozumienia kodu, dzięki któremu obiekty te działają. Użycie technologii Microsoft IntelliSense Aby używać obiektu, programista musi jedynie określić jego właściwość lub metodę przy użyciu technologii IntelliSense (rysunek 11.2). Przykładowo, jeden ze znajdujących się na naszej płycie CD obiektów to obiekt służący do obsługi błędów w aplikacjach Accessa. Ponieważ cały kod tego obiektu zawarty jest w obiekcie cError, programista musi tylko określić cechy swojego obiektu oraz właściwość lub metodę, której chce użyć. Przykładowo, gdyby programista chciał, by konsekwencją wystąpienia błędu w aplikacji było wysłanie e-maila, wystarczyłoby odwołanie do metody „e-mail”: cError.email Rysunek 11.2. Obiekty umożliwiają Ci użycie technologii Microsoft IntelliSense Zauważ, jak proste jest używanie obiektów. Korzystając z technologii Microsoft IntelliSense, wpisujesz po prostu nazwę obiektu (cError) i kropkę, a wyświetlone zostaną wszystkie właściwości i metody tego obiektu. To znacznie ułatwia pisanie odpowiedniego kodu. Organizowanie kodu Tworzenie klas ułatwia organizowanie kodu, co czyni go łatwiejszym do czytania, przeglądania i obsługiwania. Cały kod dotyczący konkretnego zestawu funkcji zawarty jest wewnątrz danej klasy. Umieszczanie kodu w tym samym miejscu co właściwości i metod opisujących obiekt nazywamy hermetyzacją. Dopuszczenie przeglądania obiektów w Object Browser Umieszczenie kodu w klasach umożliwia programistom użycie narzędzia Object Browser w celu przeglądania właściwości, metod i innych informacji o obiekcie. W dalszej części tego rozdziału przyjrzymy się jednemu z obiektów własnych w tym narzędziu. Tworzenie wielu egzemplarzy obiektów Wyobraź sobie, że istnieje fragment kodu, którego używasz wielokrotnie w różnych miejscach aplikacji. W rzeczywistości, kod ten może być używany niezliczoną ilość razy jednocześnie. Przykładem tego może być kod łączenia do danych. Za każdym razem, gdy użytkownik poszukuje nowego klienta, otwiera formularz lub używa listy wyboru, z serwera pobierane są dane. Zamiast tworzyć duplikat kodu w każdej z tych procedur lepiej jest utworzyć obiekt Data Connection, zawierający kod, który będzie służył do pobierania danych z serwera. Tworzenie kodu łatwego do aktualizacji i utrzymania Używając klas, możesz w aplikacji wielokrotnie użyć jednostki kodu bez powtarzania go. Jeśli, przykładowo, w wielu procedurach powtarzasz kod dostępu do danych, w przypadku gdy zajdzie potrzeba wprowadzenia zmian, każde miejsce, w którym znajduje się ten kod, musi zostać odnalezione i zmodyfikowane. Postępowanie takie jest bardzo czasochłonne i mało wydajne. Gdyby w tej sytuacji użyć obiektu Data Connection, aktualizacja i wszystkie zmiany w kodzie dostępu do danych byłyby dokonywane w jednym miejscu – module klasy. Ograniczenie dostępu do kodu Klasy umożliwiają Ci sprawowanie kontroli nad tym, kto i w jakich okolicznościach używa kodu. Dzięki klasom możesz zabezpieczać właściwości i metody, kontrolując ich pojawianie się na zewnątrz klasy. Tworzenie przenośnego kodu Ponieważ moduł klasy jest odrębną jednostką kodu, może być z łatwością przenoszony z jednej aplikacji Accessa do innych. Przegląd obiektów, właściwości i metod Zanim przejdziemy do tworzenia obiektów, zatrzymajmy się przy podstawowych wiadomościach. Jeśli nie będziemy mieli jasności co do terminów: obiekt, właściwości i metody, przejście do dalszej części rozdziału nie będzie miało sensu. Obiekt jest to element, który może być programowany, obrabiany i kontrolowany. W Accessie obiektami są formularze, pola tekstowe, przyciski poleceń i inne. W tym rozdziale zajmiemy się tworzeniem własnych obiektów. Właściwość jest to cecha obiektu. Może być ona postrzegana jako przymiotnik, gdyż opisuje i charakteryzuje obiekt. W Accessie właściwościami pola tekstowego są: Nazwa, Widoczny, Kolor pierwszego planu i inne. Większość właściwości obiektu może być zarówno ustawiana, jak i pobierana. W tym rozdziale pokażem,y jak tworzyć własne właściwości i kontrolować, czy będą one ustawiane, czy pobierane. Metoda jest to czynność, jaką można wykonać na obiekcie. Może być ona postrzegana jako czasownik. Przykładowo, jedną z metod w formularzu Accessa jest Close. W tym rozdziale pokażemy, jak tworzyć własne metody dla obiektów. Tworzenie klas Do tworzenia klasy używany jest moduł klasowy. Klasa definiuje właściwości, metody i zdarzenia, tworząc jasno określony i dobrze opisany interfejs. Wstawianie modułu klasowego Tworzenie klasy jest bardzo proste. Trochę więcej wysiłku wymaga dodawanie do obiektu właściwości i metod. Aby utworzyć klasę, wstaw do swojej aplikacji moduł klasy i nazwij go. Nazwa tego modułu klasy będzie nazwą Twojego obiektu. Aby wstawić moduł klasy, z menu Wstaw wybierz Moduł klasy. Uruchomiony zostanie edytor VBA. W oknie kodu możesz wpisywać dowolne właściwości, metody i zdarzenia dla obiektu. Zanim przejdziemy dalej, nazwij ten moduł klasowy (rysunek 11.3). Rysunek 11.3. Używaj jednolitego nazewnictwa modułów klasy Zwracaj uwagę na nazewnictwo modułów klasy, gdyż będą to nazwy Twoich obiektów. W ten sposób programiści, przy użyciu technologii IntelliSense, będą uzyskiwali dostęp do napisanego przez Ciebie kodu. Warto również poprzedzić nazwę obiektu inicjałami firmy, aby móc później bez trudu stwierdzić, który z obiektów został stworzony przez Twoją firmę. Tworzenie właściwości Istnieją dwa sposoby tworzenia właściwości klasy: zmienne jawne i procedury właściwości. Kod znajdujący się na dołączonej płycie CD zawiera wiele obiektów. Najprostszy z nich, obiekt cUser, wykorzystamy jako przykład na następnych stronach. Obiekt cUser przechowuje informacje o aktualnie zalogowanym użytkowniku, w tym jego lub jej imieniu. Obiekt ten może być użyty, gdy aplikacja wymaga imienia użytkownika, na przykład przy obsłudze błędów czy przy zapisywaniu autora notatek czy dokumentów. W naszym przykładzie wykorzystamy obiekt cUser do zapisywania dat i czasów logowania użytkowników, a jedno ze zdarzeń tego obiektu wykorzystamy do wyświetlenia wiadomości witającej użytkownika po zalogowaniu. Użycie zmiennych publicznych Właściwość może zostać utworzona przez zadeklarowanie zmiennej publicznej w części deklaracyjnej modułu klasowego. Poniższy przykład tworzy właściwości Imię i TypUżytkownika obiektu cUser: Public Imię as String Public TypUżytkownika as String Po wykonaniu tego prostego kroku użytkownicy mogą ustawiać i pobierać wartości tych właściwości. Do ustawienia tych właściwości służy następujący kod: cUser.Imię = "Michał" cUser.TypUżytkownika = "Kierownik" Aby pobrać tę właściwość, wystarczy użyć następującego kodu (rysunek 11.4): MsgBox cUser.Imię Rysunek 11.4. Ustawianie i pobieranie właściwości obiektów jest proste dzięki technologii IntelliSense Użycie procedur właściwości Właściwości mogą być dodawane do obiektów za pomocą specjalnego typu procedur VBA – procedur właściwości. Istnieją trzy rodzaje procedur właściwości: Property Let dla pobierania wartości właściwości, Property Get dla ustawiania wartości właściwości oraz Property Set, która umożliwia traktowanie obiektów jak właściwości. Procedury właściwości umożliwiają Ci określenie, kto może ustawiać i pobierać wartości właściwości. Kluczem do zrozumienia funkcjonowania procedur właściwości jest to, że wartość właściwości ukryta jest w zmiennej prywatnej modułu. Stąd też, pierwszy krok to utworzenie zmiennej prywatnej modułu, a następnie tworzenie instrukcji Property Let i Property Get. Procedury właściwości, podobnie jak wszystkie inne procedury, mogą być ustawiane jako jawne i niejawne. Jawne procedury właściwości dostępne są dla wszystkich innych procedur we wszystkich modułach. Niejawne procedury właściwości dostępne są jedynie dla procedur w module, w którym zostały zadeklarowane. Tworzenie w module zmiennych prywatnych Gdy używamy procedur właściwości, wartość właściwości ukryta jest w zmiennej prywatnej modułu. Osoba tworząca klasę określa, czy właściwość ma być dostępna na zewnątrz, czy nie. Poniżej znajduje się przykład tworzenia zmiennej niejawnej modułu dla właściwości Imię i TypUżytkownika obiektu cUser: Option Explicit ' Utwórz zmienną prywatną w części deklaracyjnej' Private mstrImię as String Private mTypUżytkownika as String Property Let Procedura Property Let używana jest do ustawiania wartości właściwości. Jeśli nie chcesz, aby inni mieli możliwość ustawiania wartości właściwości, nie dołączaj tej procedury. Poniższy przykład tworzy procedurę Property Let dla właściwości Imię obiektu cUser: Public Property Let Imię (ImięUżytkownika as String) ' Weź wartość wpisaną do (ImięUżytkownika) i zapisz ją w zmiennej ' prywatnej (mstrImię). mstrImię = ImięUżytkownika End Property Przyjrzyjmy się teraz tej procedurze. Po pierwsze, jako że procedura Property Let istnieje, właściwość Imię jest dostępna na zewnątrz i może zostać ustawiona. Programista mógłby ustawić tę właściwość w następujący sposób: cUser.Name = "Mariusz" Gdy Mariusz zostanie wprowadzony w procedurze właściwości, zostanie przekazany do zmiennej ImięUżytkownika. Procedura Property Let pobiera wartość zmiennej ImięUżytkownika (Mariusz) i ukrywa ją w zmiennej prywatnej modułu – mstrImię. Procedura ta dotyczy jednego parametru, ale do procedury właściwości można przekazać ich wiele. Wartość właściwości może być pobrana tylko wtedy, gdy istnieć będzie procedura Property Get. Property Get Procedura Property Get umożliwia pobieranie wartości właściwości. Jeśli nie chcesz, by inni mogli pobierać wartość właściwości, nie dołączaj instrukcji Property Get. Instrukcja ta pobiera wartość właściwości ukrytą w zmiennej prywatnej i zwraca ją jako wartość właściwości. Poniższy przykład zawiera instrukcję Property Get dla właściwości Imię obiektu cUser: Public Property Get Imię () as string ' Weź wartość ukrytą w zmiennej prywatnej (mstrImię) i ' umieść ją w wartości właściwości. Imię = mstrImię End Property Użytkownik może z łatwością pobrać wartość właściwości (jeśli instrukcja Property Get istnieje), korzystając z poniższego kodu: MsgBox cUser.Imię Typ danych Property Let musi być taki sam jak Property Get. Przykładowo, instrukcja Property Let dla właściwości Imię akceptuje argument typu string (ciąg). W takim przypadku, procedura Property Get musi również zwracać dane typu string. Property Set Instrukcja Property Set umożliwia Ci tworzenie procedury właściwości, która ustawia odniesienie do dowolnego obiektu. By określić obiekt, użyj w procedurze Property Set słowa kluczowego Set. W naszym przykładzie użyliśmy obiektu cForm. Obiekt ten posiada właściwość Form, do której musi być przekazany obiekt Form. Kod w module klasy cForm jest następujący: Option Compare Database ' Zadeklaruj zmienną prywatną na poziomie modułu Private mobjForm as Form Public Property Get Form() As Variant ' Pobierz obiekt znajdujący się w zmiennej prywatnej (mobjForm) i ' umieść go w wartości właściwości. Set Form = mobjForm End Property Public Property Set Form(FormObject) ' Pobierz przekazany obiekt (FormObject) i zapisz go ' w zmiennej prywatnej(mobjForm) Set mobjForm = FormObject End Property Po załadowaniu frmPropertySet formularz przekazywany jest do właściwości Form. Ponieważ jest to obiekt, używamy słowa kluczowego Set. Nazwa formularz może być wyświetlona w oknie komunikatu. Oto kod dla formularza frmPropertySet: ' W tym przykładzie korzystamy z obiektu "cForm". Obiekt ' ten posiada właściwość "Form". Gdy ładowany jest formularz ' (frmPropertySet), przekazywany jest jako obiekt do właściwości ' "Form". Gdy klikniesz przycisk "Property Set", pobrana zostanie ' nazwa formularza. Private mobjForm As cForm Private Sub cmdClose_Click() DoCmd.Close acForm, "frmPropertySet", acSaveNo EndSub Private Sub cmdPropertySet_Click() MsgBox "Obiekt formularz (we właściwości 'Form') nazywa się: " _ & mobjForm.Form.Name, vbInformation, "Przykład Property Set" End Sub Private Sub Form_Load() Set mobjForm = New cForm Set mobjForm.Form = Forms!frmPropertySet End Sub Private Sub Form_Unload(Cancel As Integer) Set mobjForm = Nothing End Sub Zmienna publiczna czy procedury właściwości Najprostszym sposobem tworzenia właściwości klasy jest użycie zmiennych publicznych. Jednakże rozwiązanie to ma swoje wady. Zmienne publiczne zawsze są dostępne na zewnątrz. Oznacza to, że nie masz kontroli nad tym, kto ustawia i pobiera wartości właściwości. Może to doprowadzić do sytuacji, w której inni zmieniają wartość właściwości, na której Ty się opierasz. Zaletą procedur właściwości jest to, że umożliwiają tworzenie właściwości tylko-do-odczytu i tylko-do-zapisu. Przykładowo, jeśli chcesz utworzyć właściwość Hasło, możesz chcieć pozwolić użytkownikom zmieniać je, ale nie pobierać (tylko-do-zapisu). Aby utworzyć procedurę tylko-do-zapisu, wystarczy dołączyć instrukcję Property Let i jednocześnie nie dołączać instrukcji Property Get. Korzystając z procedur właściwości, możesz również wykonywać czynności w kodzie podczas ustawiania lub pobierania właściwości. Tworzenie wyliczeniowych typów danych Wyliczeniowy typ danych to wartość właściwości, jaką możesz dostarczyć programistom używającym Twoich obiektów. Przykładowo, być może zauważyłeś, że gdy podczas ustawiania właściwości Widoczny formularza wpiszesz znak równości, będziesz mógł z rozwijanej listy wybrać wartości True lub False (rysunek 11.5). Rysunek 11.5 Z rozwijanej listy wybierz True lub False Możesz dostarczać takie wartości właściwości, tworząc typy wyliczeniowe. W części deklaracyjnej modułu klasowego do określenia wartości właściwości użyj słowa kluczowego Enum. Przykładowo, załóżmy, że dla właściwości TypUżytkownika obiektu cUser chcesz dostarczyć rozwijaną listę z następującymi wartościami: Menedżer, Administracja oraz Nieznany. Kod w części deklaracyjnej będzie następujący: Public Enum ListaUżytkowników Menedżer Administracja Nieznany End Enum Następnym krokiem będzie użycie wyliczeniowego typu danych (ListaUżytkowników) jako typu danych właściwości TypUżytkownika klasy cUser. Ilustruje to poniższy przykład, z właściwością utworzoną jako zmienna jawna: Przykład 1. Właściwość zadeklarowana jako zmienna string Public TypUżytkownika as String Przykład 2. Właściwość zadeklarowana jako wyliczający typ danych Public TypUżytkownika as ListaUżytkowników Wartości właściwości mogą być bez trudu ustawiane przy użyciu rozwijanej listy, dostępnej dzięki technologii IntelliSense (rysunek 11.6). Rysunek 11.6. Przykład wyliczeniowego typu danych Aby można było określić, która ze znajdujących się na liście wartości właściwości została wybrana, każdy typ danych jest numerowany (rozpoczynając od zera, z przyrostem równym 1). Wprowadzone wartości właściwości nie są ograniczone do wyliczeniowych typów danych. W poprzednim przykładzie, wyliczeniowy typ danych zawierał trzy elementy: Menedżer, Administracja i Nieznany. VBA nie uniemożliwia programiście zignorowania wartości z listy i wpisania innych (na przykład Produkcja). Aby ograniczyć możliwość wyboru do listy, użyj wartości liczbowych elementów z listy. Przykładowo, jeśli na liście są trzy elementy (i numerowanie rozpoczyna się od zera), możesz uniemożliwić wprowadzanie elementów mniejszych niż zero i większych niż dwa. Tworzenie metod Metoda jest to czynność, jaką możemy wykonać na obiekcie. Aby utworzyć metodę dla klasy, wystarczy utworzyć publiczną procedurę lub funkcję. Załóżmy, że za każdym razem, gdy użytkownik loguje się do aplikacji, chcesz zapisywać czas i datę tego zdarzenia. Poniższy kod utworzy metodę Login, wprowadzającą do tabeli datę i czas zalogowania każdego z użytkowników. Public Sub Login() ' Utwórz zmienną obiektu dla zestawu rekordów Dim rst As ADODB.Recordset ' Utwórz zmienną string Dim strSQL As String ' Instrukcja SQL dla tblUsers strSQL = "Select * FROM tblUsers" ' Utwórz zestaw rekordów ADO Set rst = New ADODB.Recordset ' Otwórz zestaw rekordów rst.Open strSQL, CurrentProject.Connection, adOpenKeyset, _ adLockOptimistic ' Dodaj nowy rekord rst.AddNew ' Zapisz czas i datę logowania użytkownika With rst !Imię = Me.Name !Data = Date !Czas = Time End With ' Zapisz nowy rekord rst.Update ' Zamknij zestaw rekordów rst.Close ' Zniszcz zmienną obiektu Set rst = Nothing End Sub Użycie metod Do użycia metody przy otwieraniu aplikacji służy następujący kod: cUser.Login Zauważ, że użytkownicy tej metody nie muszą rozumieć kodu ADO, aby aktualizować wartość w bazie danych. Wystarczy, że używają właściwości i metod dostępnych dla obiektu wyświetlanego przez IntelliSense. Tworzenie zdarzeń Obiekty w Accessie posiadają swoje zdarzenia. Przykładowo, obiekt formularz posiada zdarzenie Przy załadowaniu, a przycisk polecenia zdarzenie Przy kliknięciu. Dla własnych obiektów również możesz tworzyć zdarzenia. W tym celu musisz użyć w części deklaracyjnej słowa kluczowego Event i określić nazwę zdarzenia. Przykładowo, dodajmy zdarzenie Przy powitaniu, które będzie występowało po otwarciu aplikacji przez użytkownika. W części deklaracyjnej modułu klasy umieść poniższy kod, który utworzy wyrażenie: Event PrzyPowitaniu () Aby użyć zdarzenia, umieść je w metodzie obiektu. Służy do tego polecenie Raise. W naszym przykładzie, umieścimy zdarzenie Przy powitaniu w metodzie Login obiektu cUser. Gdy użytkownik uruchomi aplikację, nastąpi odwołanie do metody Login. Spowoduje to uruchomienie zdarzenia Przy powitaniu, które wyświetli ekran powitalny dla użytkownika, zawierający jego Imię. Służy do tego następujący kod: Public Sub Login() RaiseEvent PrzyPowitaniu End If Te kroki wystarczą, by utworzyć zdarzenie i umieścić je w module klasy. W następnej części omówimy użycie zdarzeń w formularzu. Użycie zdarzeń Aby użyć zdarzenia Przy powitaniu z modułu formularza, w części deklaracyjnej zadeklaruj zmienną obiektu cUser i użyj słowa kluczowego WithEvents. Umieszczenie tego słowa konieczne jest do użycia zdarzeń obiektu cUser. Użyj następującego kodu: ' W części deklaracyjnej modułu umieść Private WithEvents objUser As cUser Słowo kluczowe WithEvents może być używane jedynie w modułach klasowych (takim właśnie są moduły formularza). Nie można go jednak używać w standardowych modułach. Po zadeklarowaniu używającej słowa kluczowego WithEvents zmiennej na poziomie modułu przyjrzyj się znajdującym się u góry okna modułu listom wyboru. W lewym polu wybierz obiekt cUser. Następnie w prawej liście wyboru zobaczysz zdarzenia dla tego obiektu. Wybierz zdarzenie Przy powitaniu, a procedura zostanie wyświetlona w oknie kodu. Tam też będziesz mógł wpisać kod, który będzie reakcją na zdarzenie. Poniższy przykład zawiera kod będący reakcją na zdarzenie Przy powitaniu (rysunek 11.7). Rysunek 11.7. Procedura używająca zdarzenia „Przy powitaniu” obiektu cUser W wyniku tego, przy otwieraniu aplikacji przez użytkownika wyświetlany będzie ekran powitalny (rysunek 11.8). Rysunek 11.8. Ekran powitalny Uruchamianie zdarzeń „Przy inicjacji” i „Przy zakończeniu” Moduły klasy zawsze posiadają zdarzenia Przy inicjacji i Przy zakończeniu. Aby użyć tych zdarzeń, wybierz je ze znajdującej się u góry okna kodu listy wyboru. Zdarzenie Przy inicjacji uruchamiane jest za każdym razem, gdy obiekt jest tworzony. Przykładowo, jeśli chcesz, aby określony kod był uruchamiany, gdy tworzony jest obiekt cUser, umieszczasz go w zdarzeniu Przy inicjacji. Zdarzenie Przy zakończeniu uruchamiane jest za każdym razem, gdy obiekt jest niszczony. Jest to dobre miejsce na umieszczenie kodu porządkującego, który zamknie połączenia bazy danych, zwolni zmienne obiektów itp. Użycie obiektów W tym momencie, obiekt cUser istnieje i posiada właściwości oraz metody. Aby użyć go w module klasy, wystarczy wpisać nazwę tego obiektu oraz kropkę. IntelliSense wyświetli listę właściwości i metody dla tego obiektu. Aby użyć obiektu wewnątrz klasy, która go stworzyła, użyj słowa kluczowego Me. Przykładowo, aby ustawić nazwę użytkownika: Me.User = "Mariusz" Użycie tego obiektu z zewnątrz modułu klasy cUser (w formularzach lub modułach standardowych) wymaga wykonania dwóch czynności. Po pierwsze, zadeklarowania zmiennej obiektu, która zostanie użyta jako odniesienie do obiektu. Drugą czynnością jest wykorzystanie słowa kluczowego Set do utworzenia odniesienia zmiennej obiektu do obiektu. Tworzenie zmiennej obiektu Zmienna jest to fragment pamięci, zarezerwowany w celu przechowywania bądź pobierania informacji. Z pewnością miałeś już do czynienia ze zmiennymi „prostymi” np. string (ciąg znaków) czy integer (liczba całkowita). Poniżej znajdziesz przykłady deklarowania i użycia dwóch prostych zmiennych: Dim strImię as String Dim I as Integer StrImię = "Mariusz" I = 10 W tych przypadkach, zmienne zawierały określony typ danych, a informacje w nich przechowywane mogły być w razie potrzeby pobierane. Zmienna obiektu, podobnie do prostych zmiennych, deklarowana jest za pomocą polecenia Dim: Dim objUser as cUser Przypisywanie zmiennej obiektu do obiektu Do tworzenia odniesienia między zmienną obiektu a obiektem używamy słowa kluczowego Set. Na przykład: Set objUser = New cUser Zawsze używaj instrukcji Dim i Set w osobnych liniach. Nigdy nie łącz ich w jednej linii (np. Dim objUser = New cUser). Jeśli to zrobisz, kod będzie działał dużo wolniej, a Ty nie będziesz wiedział, w którym momencie obiekt umieszczany jest w pamięci. Użycie obiektu Po utworzeniu i ustawieniu zmiennej obiektu będziesz mógł za pomocą IntelliSense używać właściwości i metod obiektu. Właściwości mogą być ustawiane i pobierane, a metody wykonywane przy użyciu składni z kropką. Ustawienie wartości właściwości: Obiekt.Właściwość = Wartość Pobranie wartości właściwości: MsgBox Obiekt.Właściwość Jeśli, próbując użyć obiektu, zauważysz, że IntelliSense nie pokazuje żadnych właściwości i metod, może to oznaczać, że nie utworzyłeś bądź nie ustawiłeś zmiennej obiektu. Zdarza się jednak, że IntelliSense nie pokazuje właściwości ani metod, mimo iż kod jest poprawny. Załóż, że napisany przez Ciebie kod jest poprawny i przetestuj go. Microsoft nie dostarczył technologii IntelliSense dla każdego elementu kodu. Zwalnianie obiektu Gdy zakończyłeś już pracę ze zmienną obiektu, zwolnij go, ustawiając obiekt na Nothing. W ten sposób odzyskasz zarezerwowane zasoby. Prawidłowa składnia wygląda następująco: ' Zwolnij zmienną obiektu Set objUser = Nothing Gdy opisujesz zmienną obiektu, przejdź od razu na koniec procedury i ustaw zmienną na równą Nothing. Dzięki temu nie zapomnisz jej zwolnić po napisaniu długiej procedury. Tworzenie wielu egzemplarzy obiektów Klasa posiada zdefiniowany zestaw właściwości i metod. To jak szablon lub schemat. Wyobraź sobie, że otwierasz nowy dokument w Wordzie. Masz wówczas możliwość użycia szablonu, na przykład List elegancki. Po wybraniu szablonu dostosowujesz go do własnych potrzeb. Lecz zmian dokonujesz już na nowym dokumencie, nie na szablonie. Dokładnie tak samo funkcjonują klasy. Po utworzeniu klasy powstaje kopia obiektu zawierająca podstawowy zestaw właściwości i metod (szablon). Od tego momentu, obiekt staje się unikatowy i posiada własny zestaw wartości właściwości oraz metod. Jedną z korzyści modułu klasy jest to, że można tworzyć wiele egzemplarzy klasy. Każda z nich posiada podstawowy zestaw właściwości i metod, jednak każdą z nich można w różny sposób dostosowywać po utworzeniu obiektu. Załóżmy, że utworzono pięć obiektów cUser. Każdy z nich posiada różne wartości właściwości i metody. Przykładowo, jeden z nich może mieć wartość właściwości Imię Mariusz, a inny Beata. Aby utworzyć kilka egzemplarzy obiektu, wystarczy stworzyć dodatkowe zmienne obiektu i przypisać każdą z nich do nowego obiektu. Przyjrzyj się poniższemu fragmentowi kodu: Public Sub WieluUżytkowników() Dim objUser1 as cUser Dim objUser2 as cUser Set objUser1 = New cUser Set objUser2 = New cUser ObjUser1.Imię = "Mariusz" ObjUser2.Imię = "Beata" Msgbox "Aktualni użytkownicy to: " & objUser1.Imię & " i "_ objUser2.Imię Set objUser1 = Nothing Set objUser2 = Nothing End Sub Przegląd innych obiektów Przykłady z tego rozdziału zawierają wiele klas, które możesz używać dla swoich potrzeb („tworzenie obiektów przy użyciu modułów klasy.mdb” na dołączonej do książki płycie CD). Teraz omówimy pokrótce każdy z tych obiektów. Obiekt TextFile Kod tego rozdziału zawiera obiekt cTextFile, który może być użyty do odczytywania i zapisywania informacji w pliku tekstowym (rysunek 11.9). Rysunek 11.9. Przykład obiektu TextFile Moduł klasowy zawiera następujący kod: Private pintFreeFile As Integer Private pvarInfo As Variant Public Function ReadLineText(strFileName As String) As String pintFreeFile = FreeFile Open strFileName For Input As pintFreeFile Line Input #pintFreeFile, pvarInfo ReadLineText = pvarInfo Close #pintFreeFile End Function Public Function ReadAllText(strFileName As String) As String pintFreeFile = FreeFile Open strFileName For Input As pintFreeFile Do Until VBA.EOF(pintFreeFile) Line Input #pintFreeFile, pvarInfo ReadAllText = ReadAllText & vbCrLf & pvarInfo Loop Close #pintFreeFile End Function Public Sub WriteLineText(strFileName As String, strText As String) pintFreeFile = FreeFile Open strFileName For Append As pintFreeFile Write #pintFreeFile, strText Close #pintFreeFile End Sub Obiekt Timer W kodzie rozdziału znajduje się również moduł klasy cTimer. Moduł ten ma dwa zastosowania: stoper (pozwala obserwować mijający czas) oraz do powstrzymania wykonywania kodu przez określoną ilość sekund. Kod w module klasy cTimer jest następujący: Option Explicit Private msngStart As Single Public Sub Wait(lngSeconds As Long) Do Until Timer > msngStart + lngSeconds DoEvents Loop End Sub Public Sub StartTimer() msngStart = Timer End Sub Public Function ElapsedTime() As Long Dim sngTimerStop As Single sngTimerStop = Timer ElapsedTime = sngTimerStop - msngStart msngStart = 0 sngTimerStop = 0 End Function Formularz frmTimer w bazie „tworzenie obiektów przy użyciu modułów klasy.mdb”” przedstawia, jak korzystać z zegara w celu określenia pozostającego czasu i stworzenia „stanu oczekiwania”. Patrz rysunek 11.10. Rysunek 11.10. Użycie zegara do określenia pozostającego czasu oraz stworzenia „stanu oczekiwania” Obiekt Sound Zadaniem modułu klasy cSound jest odtwarzanie dźwięków w aplikacjach Accessa. Moduł ten zawiera tylko jedną metodę (PlaySound), która przekazuje plik dźwiękowy do interfejsu API systemu Windows: ' Odwołanie do interfejsu API systemu Windows Private Declare Function sndPlaySound Lib "winmm.dll" Alias _ "sndPlaySoundA" (ByVal lpszSoundName As String, ByVal uFlags _ As Long) As Long Public Sub PlaySound(SoundFile As String) ' Odtwarzanie pliku dźwiękowego sndPlaySound SoundFile, 1 End Sub Poniższy kod korzysta z obiektu objSound (rysunek 11.11): Dim objSound As cSound Set objSound = New Sound ' Jeśli używasz Windows NT, wpisz ścieżkę "C:\WINNT" objSound.PlaySound "C:\Windows\chimes.wav" Set objSound = Nothing Rysunek 11.11. Przykład obiektu Sound Obiekt Letter Zadaniem tego modułu klasy jest tworzenie listów w programie Microsoft Word. Listy te tworzone są przy użyciu korespondencji seryjnej. Do stworzenia listu wykorzystywany jest szablon programu Word, a instrukcja SQL pobiera dane do listu. Metoda ShowWord (logiczna) określa, czy Word będzie widoczny dla użytkownika. Czasami możesz chcieć przesłać listy bezpośrednio do drukarki, bez ich edycji. Oto kod modułu klasy cLetter: Option Explicit Private objWord As Word.Application ' Zmienne lokalne, do przechowywania wartości właściwości Private mvarTemplate As String ' lokalna kopia Private mvarSQLStatement As String 'lokalna kopia Public Property Let SQLStatement(ByVal vData As String) mvarSQLStatement = vData End Property Public Property Get SQLStatement() As String SQLStatement = mvarSQLStatement End Property Public Property Let Template(ByVal vData As String) mvarTemplate = vData End Property Public Property Get Template() As String Template = mvarTemplate End Property Public Sub CreateLetter(DatabasePath As String, ShowWord As Boolean) ' Zapisywanie danych o klientach do pliku tymczasowego, ' który zostanie użyty do korespondencji seryjnej. ' Rozwiązanie to jest szybsze niż ' pobieranie danych bezpośrednio z Accessa. DoCmd.OutputTo acOutputQuery, "qryCustomers", _ acFormatRTF, "C:\Temp.RTF", False objWord.Documents.Add (Me.Template) ' Uruchomienie korespondencji seryjnej With objWord.ActiveDocument.MailMerge .MainDocumentType = wdFormLetters .OpenDataSource Name:="C:\Temp.rtf" .Destination = wdSendToNewDocument .Execute End With If ShowWord Then Me.ShowWord End If End Sub Friend Sub ShowWord() ' Word widoczny dla użytkownika objWord.Visible = True End Sub Private Sub Class_Initialize() ' Przejście do linii występującej po błędzie On Error Resume Next ' Próba odwołania do Worda, który już jest otwarty Set objWord = GetObject(, "Word.Application") ' Jeśli PRAWDA, Word nie jest uruchomiony If objWord Is Nothing Then ' Utwórz nowy egzemplarz aplikacji Word Set objWord = New Word.Application ' Jeśli PRAWDA, MS Word nie jest zainstalowany If objWord Is Nothing Then MsgBox "MS Word nie jest zainstalowany na tym komputerze" End If End If End Sub Private Sub Class_Terminate() Set objWord = Nothing End Sub Poniższy kod korzysta z właściwości i metod obiektu objLetter: ' Wymiary zmiennych Dim objLetter As cLetter Dim strPath As String StrPath = CurrentProject.Path ' Przydziel zmienne obiektu do obiektu cLetter Set objLetter = New cLetter ' Szablon Word'a, który będzie użyty w dokumencie objLetter.Template = strPath & "\Business Services Letter.Dot" ' Instrukcja SQL użyta do pobrania danych dla formularza objLetter.SQLStatement = "SELECT * FROM tblCustomers" ' Odwołanie do metody "CreateLetter" w celu stworzenia listu objLetter.CreateLetter strPath & "\Objects.mdb", True " Zniszczenie zmiennej obiektu Set objLetter = Nothing Obiekt Outlook Moduł klasy cOutlook służy do wyświetlania formularza Nowa wiadomość programu MS Outlook (rysunek 11.12). Jeśli chcesz umożliwić użytkownikom pisanie wiadomości programu Outlook w aplikacjach Accessa, wystarczy, że odwołasz się do metody NewEmailMessage. Oto kod zawarty w module klasy cOutlook: Option Explicit Private mobjOutlook As Outlook.Application Private mMyItem As Object Public Sub NewEmailMessage(EmailAddress As String) ' Tworzenie nowej wiadomości programu Outlook Set mMyItem = mobjOutlook.CreateItem(olMailItem) Rysunek 11.12. Wyświetlanie formularza Nowa wiadomość programu Outlook w aplikacjach Accessa mMyItem.To = EmailAddress mMyItem.Display End Sub Private Sub Class_Initialize() ' Nie zachodzi konieczność użycia instrukcji "GetObject" ' Outlook zawsze otwiera tylko jedną kopię aplikacji ' Użyj słowa kluczowego "New" ' Ustaw zmienną obiektu na aplikację Outlook Set mobjOutlook = New Outlook.Application ' Jeśli PRAWDA, Outlook nie jest zainstalowany If mobjOutlook Is Nothing Then MsgBox "MS Outlook nie jest zainstalowany na tym komputerze" End If End Sub Private Sub Class_Terminate() ' Zwolnij zmienną obiektu Set mobjOutlook = Nothing End Sub Poniższy kod odwołuje się do metody NewEMailMessage: ' Deklaracja zmiennej obiektu Dim objOutlook As Outlook ' Przydziel zmienne obiektu do obiektu cOutlook Set objOutlook = New Outlook ' Odwołanie do metody "NewEMailMessage" objOutlook.NewEMailMessage "redakcja@helion.com.pl" ' Zniszczenie zmiennej obiektu Set objOutlook = Nothing Implementacja obiektu obsługi błędów W przykładowym kodzie dla rozdziału 13. „Profesjonalna obsługa błędów” znajdziesz obszerny moduł klasowy zajmujący się obsługą błędów i obejmujący: ? Zapisywanie błędów w tabeli Accessa. ? Zapisywanie błędów w pliku tekstowym. ? Obsługę błędów związanych z pocztą elektroniczną. ? Obsługę błędów zapisu w kalendarzu programu Outlook. Używając narzędzia Object Browser, przyjrzyj się obiektowi cError (rysunek 11.13). Rysunek 11.13. Obiekt cError w narzędziu Object Browser Użycie obiektów w połączeniu z kolekcjami VBA Kolekcje VBA to sposób na traktowanie obiektów własnych jako grupy. Przykładowo, jeśli istnieje pięć obiektów cUser i chcesz na każdym z nich wykonać jakieś działanie, łatwiej i efektywniej będzie traktować te pięć obiektów jak jedną grupę niż każdy z osobna. Z pewnością zapoznałeś się już z wbudowanymi kolekcjami (np. „formularze” czy „formanty”). VBA również posiada obiekt kolekcja (collection). Kolekcja jest to sposób traktowania grupy obiektów, jakby były odrębną jednostką. W życiu codziennym też spotykamy takie grpy. Dyrygent orkiestry mówi: „A teraz wstaną wszystkie instrumenty dęte”. Jest to dużo wygodniejsze rozwiązanie niż „Tomasz, Agnieszka, Marta i Rafał, wstańcie”. W podobny sposób można traktować obiekty. Najważniejsze w całej tej idei jest to, że kolekcja jest obiektem, który posiada własne metody i właściwości. Oto cechy obiektu kolekcji: ? Jest obiektem posiadającym własne metody i właściwości. ? Do kolekcji można dodawać różne typy obiektów. ? Jego rozmiar się zmienia. Rośnie wraz z dodawaniem i zmniejsza się wraz z usuwaniem obiektów. ? Elementy kolekcji nie podlegają sortowaniu. ? Elementy kolekcji są indeksowane. Indeksowanie rozpoczyna się od wartości 1. Tworzenie kolekcji VBA Ponieważ kolekcje są obiektami, tworzy się je w taki sam sposób jak obiekty. Najpierw deklaruje się zmienną obiektu, która służy jako odniesienie do kolekcji. Później za pomocą słowa kluczowego Set tworzy się odniesienie zmiennej obiektu do kolekcji. Poniższy kod tworzy kolekcję użytkowników: Dim Users as Collection Set Users = New Collection Wygodnie jest nazywać zbiory liczbą mnogą nazwy obiektów, które zawierają. Obiekt, który będzie dodawany do zbioru w naszym przykładzie, to użytkownik (User). Stąd nazwa zbioru – Użytkownicy. Właściwości i metody kolekcji VBA Obiekt collection ma bardzo prostą strukturę, na którą składa się jedna właściwość i trzy metody (tabela 11.1). Tabela 11.1. Właściwości i metody obiektu collection Nazwa Typ Opis Count Właściwość Wskazuje ilość obiektów w zbiorze Add Metoda Używana do dodawania obiektów do zbioru Remove Metoda Używana do usuwania obiektów ze zbioru Item Metoda Używana do tworzenia odniesień do obiektów zbioru. Jest to metoda domyślna Dodawanie obiektów do kolekcji Aby dodawać obiekty do zbioru, użyj metody Add. Collection.Add Item [, Key][, Before][, After] Następnie podaj zmienną obiektu dla każdego z obiektów dodawanych do kolekcji. Przykładowo, aby dodać do kolekcji dwóch użytkowników, użyj zmiennej obiektu dla każdego z nich: objUser1 i objUser2. Następny parametr to wartość Key (już znana), która będzie użyta do tworzenia odniesienia do obiektu. Jeśli wartość klucza nie jest określona, każdy obiekt w kolekcji musi być powiązany z numerem indeksu. Radzimy określanie wartości klucza. Dzięki temu pisanie kodu jest prostsze, a sam kod jest bardziej wiarygodny niż numery indeksu. Numery indeksu mogą ulec zmianie, gdy ze zbioru zostanie usunięty jakiś element lub gdy inny obiekt zostanie wstawiony w określone miejsce przy użyciu argumentów metody Add. W poniższym przykładzie dodamy dwóch użytkowników do kolekcji Użytkownicy: Dim User1 as cUser Dim User2 as cUser Dim Użytkownicy as Collection Set User1 = New User Set User2 = New User Set Użytkownicy = New Collection User1.Imię = "Mariusz" User2.Imię = "Beata" Użytkownicy.Add User1 = User1.Imię Użytkownicy.Add User2 = User2.Imię Set User1 = Nothing Set User2 = Nothing Set Użytkownicy = Nothing Powyższy kod dodaje obiekt User1 do zbioru. Jako klucz służy wartość właściwości Imię obiektu. Obiekt User2 dodany został w ten sam sposób. Zwróć uwagę na argumenty before i after (przed i po) metody Add, które określają miejsce obiektu w zbiorze. Odnoszenie się do określonych obiektów Do obiektów w kolekcji można odnosić się za pomocą numeru lub wartości klucza. Gdy odnosisz się do obiektu w kolekcji za pomocą numeru, pamiętaj, że indeksowanie tych obiektów rozpoczyna się od wartości 1. Najprostszym sposobem na odnoszenie się do obiektów kolekcji jest użycie jako klucza ich nazwy. Poniższy kod przedstawia, jak odnosić się do określonego obiektu User2, korzystając z obu tych metod. Mimo iż metoda Item nie musi być określona (gdyż jest metodą domyślną), ułatwia przeglądanie i obsługę kodu. ' Odniesienie do obiektu w kolekcji za pomocą numeru indeksu MsgBox Użytkownicy.Item(2).Type ' Odniesienie do obiektu w kolekcji za pomocą wartości klucza MsgBox Użytkownicy.Item ("Mariusz").Type Tworzenie pętli po obiektach kolekcji Najłatwiejszym i najefektywniejszym sposobem na tworzenie pętli po obiektach kolekcji jest użycie pętli For Each. Pętla For Next może być również użyta, jednakże jest wolniejsza. Aby użyć pętli For Each określ, który obiekt zbioru chcesz zbadać. A oto kod: ' Musisz zadeklarować zmienną obiektu Dim User as cUser For Each User in Users MsgBox User.Type Next User Przykład ten sprawdza każdego użytkownika w zbiorze. Zauważ, że pojedynczy użytkownicy posiadają zmienne obiektu o nazwach User1 i User2. Aby użyć pętli For Each, określ ogólną zmienną obiektu o nazwie User. Taka zmienna obiektu nie musi być przydzielona do obiektu za pomocą słowa kluczowego Set. Jest to możliwe jedynie w przypadku pętli For Each. Usuwanie pojedynczych obiektów Aby usunąć z kolekcji określone obiekty, użyj numeru indeksu lub wartości klucza. ' Usuwanie obiektu za pomocą numeru indeksu Użytkownicy.Remove 2 ' Usuwanie obiektu za pomocą wartości klucza Użytkownicy.Remove "Mariusz" Usuwanie wszystkich obiektów Aby usunąć wszystkie elementy kolekcji, nie musisz tworzyć pętli po wszystkich obiektach, a następnie wywoływać metody Remove. Dużo szybciej jest przydzielić obiekt zbiór do nowego zbioru. ' Usuwanie wszystkich elementów zbioru Set Użytkownicy = New Collection Zwalnianie zmiennej obiektu Kolekcje są obiektami, więc tak samo, jak w przypadku wszystkich obiektów, pamiętaj o zwolnieniu zmiennej obiektu przez ustawienie jej na Nothing. ' Usuwanie zmiennej obiektu kolekcja Set Użytkownicy = Nothing Rozdział 12. Usuwanie błędów w aplikacjach Accessa W tym rozdziale: ? Usuwanie błędów logicznych. ? Praca z Visual Basic Development Environment (IDE). ? Obiekt debug. ? Użycie okna Immediate. ? Użycie programu uruchomieniowego. ? Użycie kompilacji warunkowej. ? Testowanie aplikacji. ? Ćwiczenie technik usuwania błędów. Użycie dołączonych do Accessa narzędzi do usuwania błędów oraz opisanych w tym rozdziale technik usuwania błędów pozwala na znaczne skrócenie czasu tworzenia aplikacji. Warto więc je poznać, gdyż zaowocuje to zauważalnymi korzyściami w długim okresie czasu. Nie myśl, że narzędzia do usuwania błędów przydają się tylko w przypadku bardzo skomplikowanych aplikacji. Zdarza się, że nawet w najprostszych aplikacjach błędy są trudne do wykrycia. Ważne, by błędy programu zostały wykryte i poprawione jak najszybciej. Mimo iż część z nich może mieć mały wpływ na działanie programu, inne mogą naruszyć integralność bazy danych lub wywołać jeszcze poważniejsze konsekwencje. Usuwanie błędów logicznych Błędy logiczne występują, gdy wykonywany kod nie przynosi oczekiwanych rezultatów. Naruszona może być logika lub wykonywanie programu przebiega nieprawidłowo. Gdy kod jest wykonywany, lecz nie daje oczekiwanych rezultatów, spodziewaj się błędu logicznego. Większość czasu spędzonego przy uruchamianiu aplikacji zabiera wyszukiwanie i poprawianie błędów logicznych. W tym rozdziale zostaną przedstawione techniki oraz narzędzia do usuwania takich błędów. Oto kilka przykładów błędów logicznych: ? Procedura próbuje użyć pola bazy danych, które nie posiada danych (wartość null). ? Błąd w obliczeniach. ? Przetwarzanie operacji w kodzie odbywa się w nieprawidłowej kolejności. Praca z Visual Basic Development Environment (IDE) W środowisku projektowania Accessa nastąpiła radykalna zmiana. Podobnie jak inne Visual Basic 5 i 6, Word 97 i inne programy pakietów Office 97 i 2000, Access posiada teraz Visual Basic Development Environment (IDE). Jest to środowisko projektowania zawierające standardowe środki, umożliwiające projektowanie aplikacji w różnych produktach. Opisane w tym rozdziale techniki usuwania błędów mogą być użyte zarówno podczas tworzenia aplikacji w Accessie, jak i w Visual Basic i programach pakietu Office. Aby otworzyć IDE, w widoku Projekt formularza, z menu Widok wybierz pozycję Kod programu. Na IDE składają się różne okna, które mogą być dowolnie zamykane i otwierane (np. Project, Properties, Immediate i inne). Aby otworzyć w IDE określone okno, wybierz je z menu View. Zamykanie okien odbywa się poprzez kliknięcie znajdującego się w prawym górnym rogu okna przycisku zamykającego. Gdy otwierasz IDE, układ okien jest identyczny jak wtedy, gdy po raz ostatni go używałeś. Gdy formularz otwarty jest w widoku Projekt, możesz pracować z formantami i właściwościami tak jak we wcześniejszych wersjach Accessa. Jednakże, by przeglądać kod formularza, musisz otworzyć Visual Basic IDE (rysunek 12.1). W rzeczywistości, jest to odrębna aplikacja. Mimo, iż Visual Basic IDE jest osobną aplikacją, działa w połączeniu z Accessem. Jeśli aplikacja ta jest otwarta, to zostanie zamknięta w momencie, w którym zamkniesz Access. Aby zamknąć Visual Basic IDE, z menu File wybierz Close And Return to Microsoft Access. Teraz omówimy okna Visual Basic IDE. Rysunek 12.1. Visual Basic Integrated Development Environment (IDE) Project Explorer Project Explorer wyświetla listę formularzy, raportów i modułów klasy w danej aplikacji Accessa (rysunek 12.2). Rysunek 12.2. Okno Project Explorer Kliknij dowolny obiekt prawym klawiszem myszy, aby zobaczyć jego kod lub przejść do widoku Projekt formularza. Aby otworzyć Project Explorer, z menu View wybierz Project Explorer lub naciśnij klawisze Ctrl+R. Okno Code Okno Code zawiera kod formularzy, modułów i modułów klasy (rysunek 12.3). Jako programista, spędzisz wiele godzin, wprowadzając i modyfikując kod w tym oknie. Aby je otworzyć, z menu View wybierz Code lub naciśnij klawisz F7. U góry okna Code znajdują się dwie rozwijane listy. Lista z lewej strony służy do wybierania obiektów (np. formularzy czy formantów formularza). Druga lista służy do wybierania metody dla danego obiektu. Rysunek 12.3. Okno Code Okno Properties Okno Properties służy do ustawiania i przeglądania właściwości formularzy, raportów i formantów na nich umieszczanych (rysunek 12.4). Aby je otworzyć, z menu View wybierz Properties lub naciśnij klawisz F4. Rysunek 12.4. Okno Properties Okno Immediate Okno Immediate może być używane do oceny i ustawiania zmiennych, uruchamiania procedur oraz wykonywania instrukcji Debug.Print. Aby je otworzyć, z menu View wybierz Immediate window lub naciśnij klawisze Ctrl+G. Szczegóły związane z funkcjonowaniem tego okna omówimy w dalszej części tego rozdziału. Okno Locals Okno Locals przedstawia wyrażenia, wartości i typy wszystkich zmiennych, które są aktualnie analizowane. Aby je otworzyć, z menu View wybierz Locals window. Szczegóły związane z funkcjonowaniem tego okna omówimy w dalszej części tego rozdziału. Okno Watch Okno Watch może być użyte do obserwowania wartości wyrażeń podczas działania aplikacji. Aby je otworzyć, z menu View wybierz Watch window. Szczegóły związane z funkcjonowaniem tego okna omówimy w dalszej części tego rozdziału. Object Browser Aby otworzyć Object Browser, z menu View wybierz Object Browser lub naciśnij F2. Object Browser możesz używać do przeglądania obiektów, właściwości i metod (rysunek 12.5). Rysunek 12.5. Object Browser Okno Call Stack Okno Call Stack przedstawia procedury, do których nastąpiło odwołanie. Aby je otworzyć, z menu View wybierz Call Stack lub naciśnij klawisze Ctrl+L. Szczegóły związane z funkcjonowaniem tego okna omówimy w dalszej części tego rozdziału. Jak widać, w IDE można korzystać z wielu okien. Dlatego też dużo łatwiej jest pracować w rozdzielczości 1024 na 768 lub wyższych. Jeszcze lepszym rozwiązaniem jest nowa opcja systemów Windows 98 i 2000 – multi-monitor. Aby ułatwić sobie pracę z oknami, naucz się ich klawiszy skrótów. Umożliwi Ci to ich szybkie otwieranie i zamykanie. W zależności od potrzeb okna te możesz przesuwać lub zmieniać ich rozmiar. Jeśli zmienisz położenie okna, możesz mieć trudności z powtórnym umieszczeniem go na swoim miejscu. Wystarczy wówczas kliknąć dwukrotnie pasek z jego nazwą. Obiekt Debug Obiekt Debug posiada dwie metody, które są bardzo pomocne w usuwaniu błędów aplikacji – Debug.Print i Debug.Assert. Debug.Print Korzystając z Debug.Print, możesz wyświetlać informacje w oknie Immediate. Metoda ta może być wykorzystywana w samym oknie Immediate lub w kodzie. Aby wyświetlać informacje w oknie Immediate, używaj instrukcji Debug.Print w kodzie. Gdy testujesz wyrażenia lub uruchamiasz funkcje w oknie Immediate, nie musisz wpisywać Debug.Print. Zamiast tego wpisz znak zapytania ?, dzięki czemu uzyskasz ten sam rezultat. W oknie Immediate możesz testować wbudowane funkcje, wartości zestawu rekordów i inne (rysunek 12.6). Przykładowo, poniższy kod służy do testowania wbudowanej funkcji Len: Rysunek 12.6. Do testowania funkcji w oknie Immediate używaj znaku zapytania Umieszczając w kodzie Debug.Print, w oknie Immediate możesz wyświetlać wartości i inne informacje. Gdy wykonany zostanie poniższy kod, w oknie Immediate zostanie wyświetlona wartość stanu: Sub Demo() Debug.Print rst.States Select Case rst.States Case "Washington" MsgBox "Washington" Case "Oregon" MsgBox "Oregon" Case "California" MsgBox "California" End Select End Sub Okno Immediate nie przenosi tekstu do nowego wiersza, więc staraj się skrócić rezultat działania procedury. Nie musisz usuwać instrukcji Debug.Print z kodu, ponieważ ostateczny użytkownik nigdy nie zobaczy okna Immediate. Jeśli jednak instrukcji tych będzie dużo, będzie to miało wpływ na wydajność aplikacji. Debug.Assert Debug.Assert służy do warunkowego zawieszania wykonywania pojedynczych linii kodu. Przykładowo, jeśli instrukcja napotka Debug.Assert False, wstrzyma wykonywanie tej linii kodu. Umożliwia to przejrzenie aplikacji i usunięcie błędów. Nigdy nie używaj w kodzie słowa kluczowego Stop. Jeśli bowiem zapomnisz go usunąć, to nie tylko zatrzyma wykonywanie kodu, ale będzie również zatrzymywać używaną przez użytkowników aplikację. Zamiast tego zawsze używaj Debug.Assert, ponieważ ta instrukcja jest zawsze usuwana przez kompilator. Użycie okna Immediate Aby otworzyć okno Immediate, przejdź do edytora Visual Basic i z menu View wybierz Immediate Window lub naciśnij klawisze Ctrl+G. Okno to może być używane do podglądania i ustawiania zmiennych, uruchamiania funkcji i procedur oraz wyświetlania rezultatów działania instrukcji Debug.Print. Podglądanie zmiennych Aby podejrzeć wartość zmiennej w oknie Immediate, wprowadź znak zapytania, a po nim nazwę zmiennej (np. ? strName). Pamiętaj, że możesz określić wartość zmiennej, ustawiając na niej kursor myszy w trybie pauzy. Zmiana wartości zmiennych Aby zmienić wartość zmiennej w oknie Immediate, wprowadź jej nazwę, a po niej znak równości i nową wartość (np. intI = 10). Wyświetlanie wartości funkcji wbudowanych Aby wyświetlić wartość funkcji wbudowanej w oknie Immediate, wprowadź znak zapytania, a po nim nazwę funkcji (np. ? Now). Uruchamianie funkcji własnych Aby uruchamiać funkcje własne w oknie Immediate, wprowadź znak zapytania, a po nim nazwę funkcji i jej parametry (np. ? MyFunction). Uruchamianie własnych procedur Aby uruchamiać własne procedury w oknie Immediate, wystarczy wprowadzić nazwę procedury i jej parametry (np. MySubProcedure). Przed nazwą procedury nie wstawiaj znaku zapytania. Uruchamiając w oknie Immediate procedurę lub funkcję, wpisz jej nazwę bez znaku zapytania. Jeśli procedura lub funkcja jest modułem formularza, wprowadź przed jej nazwą nazwę tego formularza (np. frmTest.MySubProcedure). Wskazówki pomocne w korzystaniu z okna Immediate Ponieważ spędzisz duża część pracy odbywa się w oknie Immediate, poniższe wskazówki mogą okazać się bardzo pomocne. Uruchamianie instrukcji w oknie Immediate Aby w oknie Immediate uruchomić instrukcję kodu, umieść kursor w dowolnym miejscu tej instrukcji (nie musi to być początek ani koniec). Jeśli w oknie Immediate znajduje się kilka instrukcji kodu, nie musisz ich usuwać. Wystarczy, że umieścisz kursor w instrukcji, którą chcesz uruchomić i naciśniesz klawisz Enter. Poruszanie się po oknie Immediate Do przesuwania punktu wprowadzania używaj myszy oraz klawiszy strzałek. Naciśnięcie klawisza Home powoduje przeniesienie punktu wprowadzania na początek aktualnej linii kodu, a klawisza End na jej koniec. Klawisze PageUp i PageDown służą do poruszania się po kodzie strona po stronie. Aby przenieść punkt wprowadzania na początek okna Immediate, naciśnij klawisze Ctrl+Home. Naciśnięcie klawiszy Ctrl+End spowoduje przeniesienie punktu wprowadzania na koniec okna. Usuwanie kodu w oknie Immediate Aby zaznaczyć cały kod w oknie Immediate celem jego usunięcia, będąc na końcu kodu naciśnij klawisze Shift+Ctrl+Home. Gdy cały kod zostanie zaznaczony, wciśnij klawisz Delete. Jeśli punkt wprowadzania znajduje się na początku kodu, naciśnij klawisze Shift+Ctrl+End. Gdy kod zostanie zaznaczony, naciśnij klawisz Delete. Użycie programu uruchomieniowego Usuwanie błędów w aplikacjach Accessa 2000 nie jest trudne. Wystarczy zatrzymać wykonywanie kodu w określonych miejscach i przeglądając kod, obserwować jak program jest wykonywany. Ustawianie punktów zatrzymania Punkt zatrzymania zatrzymuje wykonywanie kodu. Aby ustawić punkt zatrzymania, umieść kursor w instrukcji i z menu Run Edytora Visual Basic wybierz Toggle Breakpoint lub naciśnij klawisz F9. Pamiętaj, że punktów zatrzymania nie można ustawiać w pustych liniach, komentarzu oraz częściach kodu zawierających instrukcję Dim. Innym sposobem na ustawienie punktu zatrzymania jest kliknięcie szarego, lewego marginesu okna kodu na wysokości danej instrukcji. Spowoduje to umieszczenie na lewym marginesie dużej, czerwonej kropki, oznaczającej obecność punktu zatrzymania. Gdy program zostanie uruchomiony, wykonywanie zostanie zatrzymane w miejscu umieszczenia punktu zatrzymania (rysunek 12.7). Moduł kodu zostanie automatycznie otwarty, a dana instrukcja zostanie podświetlona na żółto. Możesz wówczas przejść przez kod, przeglądać lub zmieniać wartości zmiennych itp. Aby usunąć punkt zatrzymania, z menu Run wybierz Clear All Breakpoints lub naciśnij klawisze Ctrl+Shift+F9. Rysunek 12.7. Wykonywanie kodu zatrzymane w punkcie zatrzymania Przechodzenie przez kod Gdy wykonywanie kodu jest wstrzymane w punkcie zatrzymania, podświetlona na żółto instrukcja nie została jeszcze wykonana. Możesz wówczas na kilka sposobów wykonywać kod. Krokowe wykonywanie kodu Aby wykonywać instrukcje kodu pojedynczo, z menu Debug Edytora Visual Basic wybierz Step Into lub naciśnij klawisz F8. Krokowe przechodzenie przez kod jest najbardziej wydajnym sposobem obserwowania, jak program jest wykonywany, oraz przeglądania wartości zmiennych w kodzie. Niektórzy programiści uważają za bardzo pomocny pasek narzędzi Debug. Aby go otworzyć, z menu View wybierz Toolbars, a następnie Debug. Wykonywanie procedur Zdarza się, że jedne procedury odwołują się do innych. Procedury, do których się odwołujesz, mogą być pewne (innymi słowy, pełni przetestowane i bezbłędne). Aby szybko wykonać te procedury i nie przechodzić pojedynczo przez każdą instrukcję kodu, z menu Debug wybierz Step Over lub naciśnij klawisz F8. Po zakończeniu wykonywania tej procedury wykonywanie kodu zostanie ponownie zatrzymane. Od tego momentu możesz kontynuować krokowe przechodzenie przez kod. Wykonywanie kodu do końca procedury Przyjmijmy, że przechodzisz przez procedurę, która zawiera odwołania do innych procedur. Gdy znajdziesz się w procedurze, do której nastąpiło odwołanie, możesz szybko wykonać resztę tej procedury i powrócić do pierwotnej, wybierając z menu Debug pozycję Step Out lub naciskając Ctrl+Shift+F8. Opcja ta przydaje się, gdy zapomniałeś użyć opcji Step Over, a już znajdujesz się w procedurze. Wykonanie do pozycji kursora Gdy przechodzisz przez kod, możesz spowodować wykonanie kodu na pełnej prędkości do miejsca, w którym znajduje się kursor. Przydaje się to w sytuacji, gdy przechodzisz przez jedną instrukcję kodu i chcesz szybko znaleźć się w innej instrukcji (np. pętle). Gdy kilkukrotnie przechodzisz przez pętlę, aby sprawdzić, czy działa poprawnie, umieść kursor na jej końcu i z menu Debug wybierz Run to Cursor lub naciśnij klawisze Ctrl+F8. Wybór kolejnej instrukcji Gdy przechodzisz przez kod, możesz ustawić, którą z instrukcji chcesz wykonywać jako następną. Aby tego dokonać, kliknij prawym klawiszem myszy wybraną linię kodu, a następnie z menu kontekstowego wybierz Set Next Statement. Kontynuacja wykonywania kodu Po przejściu przez kod i sprawdzeniu, czy działa poprawnie, możesz chcieć kontynuować jego wykonywanie z pełną prędkością. Aby tego dokonać, z menu Run wybierz Continue lub naciśnij klawisz F5. Ponowne uruchamianie kodu Po znalezieniu i poprawieniu błędów możesz uruchomić żądany fragment kodu ponownie bez zatrzymywania i ponownego uruchamiania aplikacji. Żółta strzałka na lewej krawędzi okna wskazuje, która instrukcja będzie wykonywana jako następna. Możesz kliknąć i przeciągnąć tę strzałkę do poprzedniej linii kodu i ponownie uruchomić kod, przez który uprzednio przechodziłeś. Podglądanie wartości zmiennych Podczas usuwania błędów w aplikacji możesz z łatwością określić, jaka jest wartość danej zmiennej. Wystarczy, że w trybie pauzy przesuniesz nad tą zmienną kursor myszy (rysunek 12.8). Okno Immediate może być również wykorzystane do wyświetlenia wartości zmiennych. Przykładowo, umieszczenie w oknie Immediate poniższego tekstu spowoduje zwrócenie wartości zmiennej o nazwie strName: ? strName Rysunek 12.8. Określenie wartości zmiennej w trybie pauzy Użycie podczas usuwania błędów technologii Microsoft IntelliSense Gdy pojawia się błąd programu i odnalazłeś właściwą linię, sprawdź jej składnię przy użyciu IntelliSense. Technologia ta pozwala przyspieszyć Twoją pracę, podając Ci podczas pisania kodu sugerowane właściwości i metody obiektów. Przykładowo, po wpisaniu nazwy obiektu (np. Recordset lub Application) wpisz kropkę, a zobaczysz, czy użyłeś właściwej nazwy i pisowni właściwości lub metody. Jeśli na wyświetlonej rozwijanej liście nie znajdziesz danej właściwości lub metody, będzie to oznaczać, że użyłeś nieprawidłowej składni. Użycie okna Locals Okno Locals przedstawia wyrażenia, wartości i typy wszystkich zmiennych, które są aktualnie analizowane. Aby je otworzyć, z menu View wybierz Locals window. Rysunek 12.9. Okno Locals przedstawia aktualnie analizowane zmienne Okno Locals może być wykorzystane do zmiany wartości zmiennych. Kliknij dwukrotnie wartość zmiennej i wprowadź nową wartość. Użycie okna Watch Okno Watch może być użyte do wyliczania wartości wyrażeń podczas działania aplikacji. Przykładowo, jeśli chcesz zobaczyć, w których miejscach aplikacji zmienna strName ulega zmianie, możesz do tego wykorzystać okno Watch. Pierwszy krok to wybranie z menu Debug pozycji Add Watch. W oknie dialogowym AddWatch wpisz żądane wyrażenie (np. strName = "Kowalski"). W oknie tym możesz również wybrać, czy chcesz wyliczać wartość wyrażenia w określonych procedurach, modułach czy w całej aplikacji (rysunek 12.10). Wybierz w oknie jedną z opcji Watch Type: Rysunek 12.10. Aby tworzyć wyrażenie Watch, użyj okna dialogowego Add Watch ? Watch Expression – monitoruje żądane wyrażenie. ? Break When the Value is True – zatrzymuje kod w trybie pauzy, gdy żądane wyrażenie nie jest spełnione. ? Break When Value Changes – zatrzymuje kod w trybie pauzy, gdy wartość wyrażenia ulega zmianie. Aby szybko utworzyć wyrażenie Watch, zaznacz dowolne wyrażenie kodu, a następnie z menu Debug wybierz Quick Watch lub naciśnij klawisz F9. W oknie dialogowym Quick Watch naciśnij przycisk Add. Rysunek 12.11. Użycie okna dialogowego Quick Watch Użycie okna Call Stack Aplikacja może zawierać procedury, które odwołują się do innych procedur, które z kolei odwołują się do innych procedur itd. Gdy usuwasz błędy w aplikacji, możesz się w pewnym momencie pogubić albo nie być pewnym, które procedury już były wykonywane. Pokaże Ci to okno Call Stack. Jeżeli przechodzenie przez kod to poruszanie się naprzód, to okno Call Stack umożliwia ci spojrzenie wstecz. Przedstawia, które procedur były uprzednio wywoływane (rysunek 12.12). Aby otworzyć okno Call Stack, z menu View wybierz Call Stack lub naciśnij klawisze Ctrl+L. Rysunek 12.12. Użyj okna Call Stack, aby sprawdzić, które procedury były uprzednio wywoływane Aby przejść do żądanej procedury, wybierz ją w oknie Call Stack i kliknij przycisk Show (lub po prostu kliknij dwukrotnie procedurę). Użycie kompilacji warunkowej Obsługa pojedynczej aplikacji jest dużo łatwiejsza niż tworzenie wielu wersji. Załóżmy, że Twoja aplikacja jest używana w wielu biurach. Większa część aplikacji jest ogólna i może być używana powszechnie, lecz istnieje niewielka część kodu, która musi być zindywidualizowana dla potrzeb każdego z biur. Jeśli zdecydujesz się utworzyć wiele wersji aplikacji, ich obsługa i aktualizacja będzie bardzo trudnym i męczącym zadaniem. Każdy nowy kod ogólny będzie musiał być dodany do każdej wersji. Ponadto duża ilość wersji znacznie komplikuje obsługę i rozprowadzanie aplikacji. Najlepszym rozwiązaniem jest stworzenie pojedynczej wersji aplikacji, która będzie się zachowywać w różny sposób, w zależności od okoliczności. Możesz wybrać, która część kodu aplikacji będzie kompilowana i uruchamiana warunkowo. Przykładowo, przyjmijmy, że określona część kodu uruchamiana będzie w biurze w Warszawie i nie dotyczy innych biur. Po pierwsze, wybierz stałą określającą to biuro, np. War. Wprowadź tę stałą jako argument kompilacji warunkowej dla aplikacji. W edytorze Visual Basic, z menu Tools wybierz Application’s Properties. Otwarte zostanie okno dialogowe Project Properties. Wybierz zakładkę General. W polu Conditional Compilation Arguments wpisz War = -1. Ustawia to stałą na True. Teraz możesz wprowadzić kod, który będzie wykonywany jedynie dla warszawskiej wersji aplikacji. Aby tego dokonać, umieść kod w konstrukcji kompilacji warunkowej. Na przykład: #If War Then ' Kod ten będzie uruchamiany w warszawskiej wersji ' aplikacji. #End If Kompilacja warunkowa może być również pomocnym narzędziem do usuwania błędów. Załóżmy, że często opatrujesz fragmenty kodu komentarzem. Ustaw argument kompilacji warunkowej na fComment = -1. Ten znacznik, komentarz może być używany w konstrukcji kompilacji warunkowej w celu opatrywania części kodu komentarzem: #If fComment Then 'Ten kod będzie uruchamiany #End If Pisanie solidnego kodu Nie ma sposobu na całkowite wyeliminowanie potrzeby usuwania błędów w aplikacjach. Jeśli jednak będziesz stosował się do poniższych wskazówek, prawdopodobieństwo, że kod będzie działał poprawnie i nie będzie zawierał błędów, jest większe. Deklaruj zmienne w osobnych liniach programu Dużo łatwiej jest sprawdzić, czy zmienna została zadeklarowana, jeśli zmienne umieszczane są w osobnych liniach, a nie długich ciągach znaków. Co więcej, technika ta nie powoduje spowolnienia działania skompilowanych aplikacji. Możesz również zauważyć, że dużo łatwiej jest odnajdywać zmienne, które są pogrupowane ze względu na typ danych. Deklaruj zmienne w jak najwęższym zakresie Używaj tak wielu zmiennych lokalnych, jak tylko to możliwe. To nie tylko pomoże zapobiec problemom związanym z ich zakresem, ale również poprawi wydajność. Używaj określonych typów danych Zawsze deklaruj typ danych i używaj najmniejszych, jak tylko to możliwe. Jeśli nie deklarujesz typu danych, używany jest wariantowy typ danych. Jest to nie tylko rozwiązanie mniej wydajne, gdyż wymaga zaangażowania dodatkowych zasobów, ale przede wszystkim, w zmiennej o wariantowym typie danych można umieścić dowolne dane. Często prowadzi to do błędów w programie. Przykładowo, jeśli zmienna powinna przechowywać liczby, a użyto wariantowego typu danych, mogą zostać użyte inne dane niż liczby lub obiekty, czego konsekwencją będzie błąd. Niszcz zmienne obiektów Unikaj błędów zasobów, niszcząc zmienne obiektów. Jeśli istnieje zmienna obiektu o nazwie objWord, zniszcz ją na końcu procedury, pisząc: Set objWord = Nothing Używaj słowa kluczowego TypeOf Często do procedury ogólnej możesz dołączyć formanty. Przykładowo, przekazujesz formanty pole listy i pole listy rozwijalnej do ogólnej procedury, która ładuje wartości przy użyciu metody AddItem. Jeśli przekazujesz formant inny niż wyżej wymienione pola (np. przycisk poleceń), wystąpi błąd, gdyż formant ten nie posiada metody AddItem. W procedurze użyj słowa kluczowego TypeOf, aby sprawdzić, jaki był typ przekazanego formantu. Umożliwi to uniknięcie błędu. Używaj Me zamiast Screen.ActiveForm i Screen.ActiveControl Gdy usuwasz błędy w aplikacji, aktywne jest okno Immediate. Stąd Screen.ActiveForm i Screen.ActiveControl nie będą działać. Zamiast nich użyj słowa kluczowego Me. Używaj narzędzia do obsługi błędów W przypadku wystąpienia błędu, dzięki narzędziu do obsługi błędów będziesz mógł zaoszczędzić dużo czasu, gdyż ułatwi Ci ono odnalezienie wadliwej instrukcji, informacji o typie błędu, numeru linii i itp. Więcej informacji na ten temat znajdziesz w rozdziale 13., „Profesjonalna obsługa błędów”. Używaj Option Explicit Wymuszaj deklarowanie wszystkich zmiennych, umieszczając Option Explicit u góry każdego modułu kodu. Możesz ustawić to domyślnie, zaznaczając opcję Require Variable Declaration w opcjach programu. Dzięki deklarowaniu wszystkich zmiennych unikniesz błędów związanych z błędami w pisowni ich nazw. Numeracja od 0 czy od 1? W VBA niektóre elementy numerowane są od 0, a inne od 1. Zależy to od tego, czy zaczynasz liczenie od 0 czy od 1. Przykładowo, tablice numerowane są od 0, a kolekcje od 1. Jeśli nie jesteś pewien, jak numerowany jest dany obiekt, sprawdź to. Pomyłka najprawdopodobniej zakończy się błędem. Natychmiast naprawiaj błędy Podczas tworzenia aplikacji będzie Cię kusiło, aby ignorować znalezione błędy. Przykładowo, tworząc nową opcję aplikacji, stwierdzasz błąd w innej części aplikacji. Najlepiej jest się zatrzymać i naprawić ten błąd. Jest to jednak trudne, bo jesteś skupiony na tym, co właśnie tworzyłeś. Pamiętaj jednak, ze później może być dużo trudniej odnaleźć i poprawić ten błąd. Najlepiej od razu poprawiać odnalezione błędy. Używaj komentarzy Nie oszukujmy się, kilka miesięcy, tygodni czy nawet dni po napisaniu kodu trudno jest pamiętać wszystkie szczegóły dotyczące konkretnej procedury. Pisz komentarze do kodu, a będzie on łatwiejszy w obsłudze. Komentarze nie zwalniają kodu, ponieważ są pomijane przez kompilator. Aby utworzyć komentarz, przed tekstem umieść pojedynczy cudzysłów. W oknie kodu komentarze wyświetlane są na zielono. Do zamiany tekstu w komentarz i przywrócenia stanu poprzedniego używaj znajdujących się na pasku narzędzi Edit opcji Comment Block i Uncomment Block. Używaj znaku kontynuacji wiersza Konieczność przewijania ekranu, aby zobaczyć kod, który nie mieści się na ekranie, znacznie utrudnia przeglądanie kodu. Upewnij się, że cały kod widoczny jest w oknie kodu, używając znaku (_) jako znaku kontynuacji linii. Dzięki temu linie rozdzielone tym znakiem będą traktowane jak jedna całość. Typowym przykładem może być następująca instrukcja SQL: Dim strSQL as String strSQL = "SELECT * FROM tblErrorLog" & _ "ORDER BY tblErrorLog.ErrorLogID;" Używaj krótkich procedur Długie procedury trudniej zrozumieć i usunąć z nich błędy. Dziel procedury na mniejsze części. Przyjmij, że jeśli nie jesteś w stanie wydrukować procedury na jednej stronie, powinieneś rozważyć podzielenie jej na mniejsze części. Używaj standaryzowanych konwencji nazewnictwa Użycie konwencji nazewnictwa umożliwi Tobie i innym programistom łatwiejsze zrozumienie kodu i usunięcie z niego błędów. Bardzo często zdarza się, że programista przejmujący aplikację od innego, skarży się na trudności ze zrozumieniem kodu. Użycie konwencji nazewnictwa w celu nazywania obiektów i zmiennych znacznie ułatwia proces usuwania błędów. Nigdy nie używaj Stop Nigdy nie używaj Stop, aby przejść do trybu pauzy. Jak już wspomnieliśmy wcześniej, zamiast tego używaj Debug.Assert. Poprawna składnia to Debug.Assert False. Jeśli zapomnisz usunąć Stop przed oddaniem aplikacji użytkownikom, nie będzie ona działać poprawnie, natomiast Debug.Assert jest podczas kompilacji usuwane z kodu. Nie usuwaj błędów przy użyciu okien komunikatu W przeszłości używanie okien komunikatu było powszechnie stosowaną techniką usuwania błędów w kodzie. Polegała ona na umieszczaniu w całym kodzie okien komunikatu i na ich podstawie odnajdywaniu wadliwych instrukcji: Sub Demo() MsgBox 1 Select Case rst.States MsgBox 2 Case "Washington" MsgBox 3 MsgBox "Washington" MsgBox 4 Case "Oregon" MsgBox 5 MsgBox "Oregon" MsgBox 6 Case "California" MsgBox 7 MsgBox "California" MsgBox 8 End Select MsgBox 9 End Sub Obserwując, które z okien komunikatu wyświetlane jest przed wystąpieniem błędu, możesz określić, w której znajduje się on linii. Dużo lepszym podejściem jest ustawienie punktu zatrzymania i przejście przez kod. Ustawienie punktu zatrzymania jest bardziej przydatne, gdyż: ? Jest szybsze niż wpisywanie dużej ilości okien komunikatu. ? Okna komunikatu są modalne, więc nie możesz przejść do okna kodu, aby przejrzeć kod. ? Przechodząc przez kod przy użyciu programu uruchomieniowego, możesz sprawdzać i zmieniać wartość zmiennych itp. ? Po naprawieniu błędu nie musisz usuwać wszystkich wstawionych okien komunikatu. ? Nie musisz się martwić, że przypadkowo dostarczysz użytkownikom aplikację, z której zapomniałeś usunąć okien komunikatu. Testowanie aplikacji Zanim przekażesz aplikację do rąk użytkowników, pamiętaj o dogłębnym jej przetestowaniu. Więcej informacji na ten temat znajdziesz w rozdziale 2. „Planowanie procesu rozwoju”. Ćwiczenie technik usuwania błędów Kod znajdujący się na dołączonej do książki płycie CD daje Ci możliwość przećwiczenia omówionych w tym rozdziale technik usuwania błędów (rysunek 12.13). Rysunek 12.13. Przećwicz techniki usuwania błędów dzięki znajdującym się na płycie CD przykładom kodu Rozdział 13.  Profesjonalna obsługa błędów W tym rozdziale: ? Usuwanie błędów składni. ? Usuwanie błędów logicznych. ? Usuwanie błędów wykrytych w trakcie użytkowania. ? Błędy w różnych aplikacjach. ? Obsługa błędów w procedurach zagnieżdżonych. ? Zaawansowane zagadnienia związane z błędami. Wizytówką profesjonalnej aplikacji jest jej obsługa błędów. Jeśli aplikacja nie radzi sobie poprawnie z błędami, niezależnie od tego jak jest rozbudowana, użytkownicy będą niezadowoleni. Program nie posiadający obsługi błędów może się bez ostrzeżenia zamknąć, co zwykle wywołuje u użytkowników frustrację, gdyż nie wiedzą, dlaczego to się stało i czy bezpiecznie jest kontynuować pracę. Gdy występuje błąd, użytkownicy powinni otrzymać informację o tym, jak sobie z tym poradzić. Niezrozumiałe informacje są prawie tak złe jak brak informacji (rysunek 13.1). Ilu użytkowników rozumie lub uważa za przydatne takie sformułowania jak Niedozwolona operacja, Przepełnienie czy Błąd Ogólnego Zabezpieczenia? Rysunek 13.1. Przykład nieczytelnego komunikatu o błędzie Bez kompleksowej obsługi błędów programiści mogą stracić także cenne sprzężenie zwrotne na temat tego, jak funkcje ich aplikacji są w rzeczywistości wykorzystywane. Poza tym, odnajdywanie i naprawianie błędów u klientów to bardzo czasochłonne zadanie. Nie ulega wątpliwości, że w interesie programisty jest szybkie naprawianie błędów programu. Bez narzędzi do obsługi błędów programiści muszą opierać się na opowieściach użytkowników o tym, co robili, gdy wystąpił błąd programu. Najczęstszą odpowiedzią użytkownika w takiej sytuacji jest „Nie wiem”. Prowadzi to do niepotrzebnej i czasochłonnej pracy, polegającej na odnalezieniu i poprawieniu błędów. W tym rozdziale pokażemy, jak stworzyć zaawansowane narzędzie do obsługi błędów, które pomoże zarówno użytkownikom, jak i Tobie. Istnieją trzy typy błędów programu: błędy składni, błędy logiczne oraz błędy wykryte w trakcie użytkowania. Usuwanie błędów składni Zacznijmy od najprostszego rodzaju błędów programu – błędów składni. Błędy te występują w sytuacji, gdy kod jest napisany nieprawidłowo. Na przykład, gdy nastąpił błąd w nazwie zmiennej albo słowa kluczowego lub gdy brakuje fragmentu kodu: Dim strName as Oczywiście w tym przypadku brakuje ważnej części kodu. Mianowicie nie określono typu danych. Prawidłowa instrukcja wyglądałaby w następujący sposób: Dim strName as String Jednym ze sposobów na wyeliminowanie błędów składni jest umieszczenie Option Explicit w pierwszej linii każdego modułu. Zmusi Cię to do deklarowania każdej ze zmiennych używanych w aplikacji. Deklarowanie wszystkich zmiennych ważne jest z kilku powodów. Błąd w nazwie zmiennej może mieć poważne konsekwencje. Jeśli zmienna służy do wprowadzania wartości do bazy danych, może dojść do wprowadzenia niewłaściwych danych bez żadnego ostrzeżenia. VBA traktuje po prostu nieprawidłowo nazwaną zmienną jako kolejną zmienną. W poniższym przykładzie, zmienna BankBalance w drugiej linii napisana jest z błędem: BankBalance = 4,576.98 RS!BankBalance = BankBalence VBA nie rozpozna BankBalence jako słowa kluczowego, więc przyjmie, że chcesz zadeklarować nową zmienną typu Variant z domyślną wartością Empty. W rezultacie, zamiast umieścić w bazie żądaną wartość 4,576.98, umieści tam wartość Empty. Deklarowanie zmiennych ma również znaczenie dla optymalizacji pracy aplikacji. Niezadeklarowane zmienne typu Variant zajmują dużo cennego miejsca. Przykładowo, różnice w zajmowanej przestrzeni dla zmiennej przechowującej liczbę 5 są następujące: ? Dim bytNumber as Byte (1 bajt); ? Niezadeklarowana zmienna (tylko dane liczbowe) (16 bajtów); ? Niezadeklarowana zmienna (ciąg znaków) (22 bajty). W tym przykładzie, niezadeklarowanej zmiennej przyznany jest typ danych Variant. Aby wymusić deklarowanie zmiennych, przejdź do edytora Visual Basic i z menu Tools wybierz Options. Otwarte zostanie okno dialogowe Options. Na karcie Editor włącz Require Variable Declaration (rysunek 13.2). Spowoduje to wstawianie Option Explicit u góry każdego modułu. Nie spowoduje jednak aktualizacji już istniejących, pamiętaj więc o umieszczeniu Option Explicit w każdym już utworzonym module. Rysunek 13.2. Aby wymusić deklarowanie zmiennych, wybierz Require Variable Declaration Można również spotkać inne błędy składni: Msggbox "Hi" lub EndSeb Błędy w pisowni tego typu słów zarezerwowanych powodują błędy składni. Podczas pisania kodu, jesteś zwykle o nich informowany poprzez wyróżnienie błędnie napisanego tekstu oraz ukazanie się komunikatu ostrzegawczego. W edytorze VBA wybierz z menu głównego Tools, Options. Na zakładce Editor wyłącz opcję Auto Syntax Check. Nie wyłączy to kontroli składni, a tylko usunie irytujące okna dialogowe, które pokazują się przy każdym błędzie składniowym. Błąd będzie zaznaczany poprzez zmianę koloru czcionki na czerwony. W oknie dialogowym Options możesz zmieniać niektóre z ustawień kompilatora. Na karcie General znajduje się opcja Compile on Demand, która umożliwia szybsze funkcjonowanie aplikacji, ponieważ moduły kompilowane są dopiero po ich załadowaniu do wykonania. Przy szybkości współczesnych komputerów zalecamy włączenie tej opcji w celu wyeliminowania błędów. Na tej samej karcie znajduje się opcja Background Compile. Po jej włączeniu uruchomione zostanie kompilowanie w tle, w czasie, gdy komputer jest nieaktywny. Opcja ta może wpłynąć na poprawę szybkości wykonywania aplikacji. Aby ją włączyć, opcja Compile on Demand musi być również włączona. Aby mieć pewność, że wszystkie błędy składni zostały wykryte, ważne jest, by przed oddaniem aplikacji do rąk użytkowników wszystkie moduły zostały skompilowane i zapisane. Z menu Debug wybierz Compile and Save All Modules, aby skompilować i zapisać każdy moduł w bazie danych, niezależnie od tego czy są załadowane, czy nie. Usuwanie błędów logicznych Z błędem logicznym mamy do czynienia, gdy wykonanie kodu nie przynosi oczekiwanych rezultatów. Może to być błąd w rozumowaniu lub program jest wykonywany nieprawidłowo. Gdy kod jest wykonywany, lecz nie przynosi oczekiwanych rezultatów, spodziewaj się błędu logicznego. Do usuwania błędów logicznych używaj rozbudowanego programu uruchomieniowego Microsoft Accessa. Temat ten został omówiony w rozdziale 12., „Usuwanie błędów w aplikacjach Accessa”. Usuwanie błędów wykrytych w trakcie użytkowania Nie istnieje sposób na wyeliminowanie wszystkich błędów wykrywanych w trakcie użytkowania aplikacji, lecz można się na nie przygotować. Dlatego też narzędzie do obsługi błędów jest koniecznością. W profesjonalnej aplikacji narzędzie do obsługi błędów umieszczone jest w każdej procedurze. Nic nie jest zostawione przypadkowi. Proste narzędzie do obsługi błędów Przed omówieniem zaawansowanych narzędzi do obsługi błędów zacznijmy od prostego przykładu: Sub Demo() Dim I as Integer On Error GoTo ErrorHandler ' Błąd programu w tej linii ExitHere: Exit Sub ErrorHandler: MsgBox "Wystąpił błąd" Resume ExitHere End Sub To proste narzędzie stosuje się do standardowych konwencji programowych, które omówione są w następnej części. On Error GoTo ErrorHandler Zgodnie z konwencją, instrukcja ta znajduje się u góry procedury, po instrukcjach Dim. Znajduje się tam dlatego, by każdy kod, w którym może wystąpić błąd, znajdował się za nią. Jeśli w kodzie pojawi się błąd, instrukcja GoTo przekaże kontrolę nad programem do narzędzia do obsługi błędów. Narzędzie to znajduje się przy etykiecie ErrorHandler. ErrorHandler nie jest słowem zarezerwowanym, lecz nazwą procedury (możesz użyć dowolnej nazwy). Etykiety są łatwe do odnalezienia, gdyż znajdują się na lewym krańcu procedury i występuje po nich dwukropek. ExitHere Ta etykieta jest punktem wyjścia dla procedury. Dobrym zwyczajem jest umieszczanie tylko jednego punktu wyjścia dla procedury. Jeśli procedura wykonywana jest bez błędów, wykonywany jest kod ExitHere i procedura jest zakończona. Kod w części ErrorHandler nie będzie wykonywany, gdyż znajduje się na samym końcu procedury. Wykonywanie kodu nigdy do tego miejsca procedury nie dojdzie, bo wcześniej nastąpi wyjście. Etykieta to świetne miejsce na umieszczenie kodu porządkującego. Przykładowo, można w tym miejscu zwolnić zmienne obiektu, ustawiając je na Nothing, zamknąć bazę danych, przywrócić domyślne ustawienie klepsydry lub włączyć aktualizację ekranu. Instrukcja On Error Resume Next powinna być najczęściej pierwszą instrukcją procedury wyjścia. Jest to konieczne, gdyż niektóre z instrukcji porządkujących mogą same powodować błędy. Przykładowo, jeśli przed otwarciem bazy wystąpił błąd, a zmienna obiektu ustawiona jest na Nothing w procedurze wyjścia (Set db = Nothing), spowoduje to powstanie błędu. Jeśli jest to wolna procedura, na jej początku włączasz klepsydrę i wyłączasz ją na końcu, musisz uważać, by nie „zacięła się” gdzieś pośrodku, gdy wystąpi błąd. DoCmd.Hourglass False jest przykładem kodu porządkującego, który powinieneś umieścić w kodzie ExitHere, aby był wykonywany przed procedurą wyjścia, niezależnie od tego, czy błąd wystąpił, czy nie. W kodzie ExitHere przywróć domyślne ustawienie klepsydry. Możesz włączyć ją na początku procedury. Jeśli błąd wystąpi, zanim wyłączysz klepsydrę na końcu procedury, wykonywany kod przejdzie do narzędzia do obsługi błędów, a klepsydra nie zostanie wyłączona. Jeśli w punkcie wyjścia klepsydra powraca do ustawień domyślnych, zawsze będzie wyzerowana. Poniższy fragment kodu to przykład procedury wyjścia zawierającej kod porządkujący: ExitHere: On Error Resume Next DoCmd.Hourglass False DoCmd.EchoTrue DoCmd.SetWarnings False Set rst = Nothing Set db = Nothing Exit Sub ErrorHandler W tym miejscu znajduje się narzędzie zajmujące się obsługą błędów występujących w trakcie użytkowania programu. Według konwencji znajduje się on u dołu procedury. Kod tego narzędzia będzie wykonywany tylko w przypadku wystąpienia błędu. Efektem jego działania powinno być jednak coś więcej niż okno komunikatu z poprzedniego przykładu. Radzimy dołączanie instrukcji Select Case, która umożliwi reagowanie w określony sposób na wszystkie błędy, jakie programista może przewidzieć (więcej szczegółów w innej części tego rozdziału – „Reagowanie na błędy”). Narzędzie do obsługi błędów powinno zawsze kończyć się instrukcją Resume. Resume ExitHere Tu następuje przekazanie wykonywania programu do kodu ExitHere. Przebieg programu z narzędziem do obsługi błędów Zauważ, jak zmienia się przebieg programu, w którym umieszczono narzędzie do obsługi błędów. Jeśli kod nie ma błędów, program wykonywany jest w następujący sposób: Sub Demo() On Error GoTo ErrorHandler Prawidłowy kod ExitHere: Exit Sub ErrorHandler: MsgBox "Wystąpił błąd" Resume ExitHere End Sub Jeśli któraś z instrukcji zawiera błąd, przebieg programu ulegnie zmianie, gdyż wykonany zostanie kod narzędzia do obsługi błędów: Sub Demo() On Error GoTo ErrorHandler Nieprawidłowy kod ExitHere: Exit Sub ErrorHandler: MsgBox "Wystąpił błąd" Resume ExitHere End Sub Obiekt Err VBA zawiera obiekt Err, który dostarcza wiele informacji, które możesz wykorzystać w narzędziu do obsługi błędów. Obiekt Err jest obiektem globalnym, więc nie zachodzi konieczność tworzenia jego egzemplarza. Oto właściwości obiektu Err: ? Err.Number – numer aktualnego błędu. Numer ten może by wykorzystany do reagowania na różne typy występujących błędów. ? Err.Description – opis błędu. ? Err.Source – Obiekt lub aplikacja, które wywołały błąd. ? Err.HelpFile – ścieżka dostępu do pliku pomocy Windows. Właściwość ta, użyta razem z HelpContext, umożliwia umieszczenie w oknie komunikatu przycisku Pomoc. ? Err.HelpContext – identyfikator kontekstu dla tematu w pliku pomocy. ? Err.Last DLL Error – systemowy kod błędu uzyskany przez odwołanie do biblioteki DLL. Obiekt Err posiada również dwie metody: Err.Clear Metoda Clear czyści właściwości obiektu Err. Każde z poniższych rozwiązań powoduje wyczyszczenie właściwości obiektu Err: ? Odwołanie do metody Clear obiektu Err (Err.Clear). ? Użycie dowolnej instrukcji Resume. ? Wyjście z procedury. ? Użycie instrukcji On Error. Err.Raise Metoda Raise generuje błąd związany z użytkowaniem aplikacji. Przydaje się to przy testowaniu aplikacji. Możesz wykonać symulację błędu związanego z użytkowaniem aplikacji, przekazując kod do metody Raise obiektu Err. Ponadto, gdy aplikacja odwołuje się do zewnętrznej biblioteki DLL, możesz przekazać wartość błędu z powrotem do aplikacji, która zajmie się obsługą tego błędu. Wywołując błędy, możesz generować błędy przez Ciebie definiowane. Pamiętaj jednak, by numer błędu był unikatowy i dodaj go do stałej vbObjectError. Przykładowo, aby utworzyć numer błędu 50, przydziel do argumentu numeru vbObjectError + 50: Err.Number = vbObjectNumber + 50 A oto przykład użycia metody Raise: Sub Demo (intNumber) If intNumber = 110 Then 'Wywołaj błąd Err.Raise vbObjectError + 50, "Moja Aplikacja" "Liczba nie może być większa niż 100", _ "c:\MyApp\MyApp.Hlp", MyContextID End If End Sub Metoda Raise posiada pięć argumentów: Number, Source, Description, HelpFile i HelpContext (argumenty te są takie same jak dla obiektu Err). Składnia wygląda następująco: Err.Raise (Number, Source, Description, HelpFile, HelpContext) Używając nazwanych parametrów, możesz przekazać tylko wybrane argumenty, dzięki czemu kod będzie lepiej opisany: Err.Raise Number:= vbObjectError + 50, Description:= "Błąd Własny" W poznaniu właściwości i metod obiektu Err pomoże Ci Object Browser. W dowolnym module kodu naciśnij klawisz F2, wybierz bibliotekę VBA i kliknij znajdujący się poniżej klas Err Object. Będziesz mógł przejrzeć jego wszystkie właściwości i metody. Zaznacz dowolną z nich i naciśnij klawisz F1, a wyświetlona zostanie pomoc na ten temat. Reagowanie na błędy Duża część kodu narzędzia do obsługi błędów powinna używać instrukcji Select Case. Spróbuj przewidzieć każdy możliwy błąd, który może wystąpić, i umieść jego numer na liście w instrukcji Select Case. Wówczas będziesz mógł radzić sobie z tym błędem we właściwy sposób. Z przewidywanym błędem można sobie radzić na kilka sposobów: ? Okna komunikatu przedstawiające użytkownikom informacje o błędzie. ? Okna komunikatu przedstawiające użytkownikom informacje o sposobach naprawienia błędu (np. Brak dysku w napędzie a: ). ? Zignorować błąd i kontynuować wykonywanie programu. ? Zignorować błąd i wyjść z procedury. ? Poprawić kod, by jego wykonywanie mogło być kontynuowane. ? Przejść do innego miejsca w kodzie. Sytuację tę ilustruje poniższy kod: ErrorHandler: Select Case Err.Number Case 11 If MsgBox ("Wykonałeś dzielenie przez zero, wprowadź " & _ " inną liczbę. Chcesz spróbować ponownie? ", _ vbQuestion + vbYesNo) = vbYes Then Resume Else Resume ExitHere End If Case Else MsgBox "Wystąpił nieoczekiwany błąd. Numer błędu: " & _ Err.Number & "Opis błędu: " & Err.Description Resume ExitHere End Select End Sub Możesz nawet tworzyć ogólne procedury, które będą obsługiwały błędy określonego typu. Przykładowo, jeśli przyjrzysz się w bazie danych Access and Jet errors.mdb tabeli błędów Accessa i Jet, zauważysz, że błędy o numerach między 58 a 76 dotyczą błędów plików (np. File already exists, Disk full, Too many files i inne). Mógłbyś stworzyć ogólną procedurę dla tej grupy błędów i odwoływać się do niej z instrukcji Select Case w narzędziu do obsługi błędów: ErrorHandler: Select Case Err.Number Case 58 to 76 'Ogólna procedura dla obsługi błędów plików Call FileTypeErrors Case Else MsgBox "Wystąpił nieoczekiwany błąd. Numer błędu: " & _ Err.Number & "Opis błędu: " & Err.Description Resume ExitHere End Select End Sub Instrukcje Resume Poniższe instrukcje Resume umożliwią Ci przekazanie, w przypadku wystąpienia błędu, wykonywania programu do różnych instrukcji. Resume Resume powoduje przekazanie wykonywania kodu do linii, w której wystąpił błąd. Gdy użytkownik zostanie poinformowany o sposobie rozwiązania błędu, użycie instrukcji Resume spowoduje powrót do instrukcji, w której nastąpił błąd. Ma to zastosowanie w sytuacji, w której przyczyna powstania błędu została usunięta i chcesz powrócić do tego miejsca w kodzie, w którym wystąpił błąd. Resume Next Resume Next powoduje przekazanie wykonywania kodu do linii następującej po linii, w której wystąpił błąd. Umożliwia to wykonanie pozostałej części kodu. Poniższy diagram ilustruje przebieg programu dla różnych instrukcji Resume (rysunek 13.3). Rysunek 13.3. Obsługa błędu przy użyciu instrukcji Resume Uzyskiwanie dodatkowych informacji o błędzie Narzędzie do obsługi błędów powinno automatycznie zapisywać wszelkie informacje o błędzie, które mogą okazać się przydatne dla programisty. Im więcej tych informacji zbierze, tym łatwiej będzie programiście odnaleźć i naprawić błąd. Obiekt Err dostarcza wielu informacji, lecz nie wszystkich. Dobrze zaprojektowane narzędzie do obsługi błędów powinno dostarczać następujących, dodatkowych informacji o błędzie: ? Numer linii – identyfikuje numer linii, w której wystąpił błąd. Zastanów się, czy nie warto umieścić w każdym module określonej liczby linii. Numery linii mogłyby być wstawiane po lewej stronie modułu, przed instrukcjami kodu. Dzięki opcji Find Accessa mógłbyś szybko przechodzić do linii, w której wystąpił błąd (przy założeniu, że numery linii się nie powtarzają). Numery linii w procedurze nie muszą być umieszczone po kolei. Obiekt Err nie posiada opcji numerowania linii. Aby numerować linie, użyj funkcji Erl. Przykład jej zastosowania znajdziesz w kodzie na dołączonej do książki płycie CD. ? Nazwa formularza lub raportu – przedstawia nazwę formularza lub raportu, w którym wystąpił błąd. Jest to kwestia przekazania nazwy formularza lub raportu do narzędzia zajmującego się obsługą błędów. ? Nazwa procedury – przedstawia nazwę procedury, w której wystąpił błąd. ? Nazwa aktywnego formantu – przedstawia nazwę formantu, który był aktywny w momencie wystąpienia błędu. ? Wartość aktywnego formantu – przedstawia wartość aktywnego formantu w momencie wystąpienia błędu. Zdarza się, że błąd występuje tylko w przypadku wprowadzenia określonych wartości. Przykładowo, jeśli błąd występuje, gdy w polu tekstowym wprowadzana jest wartość większa niż 20,000, to błąd taki można z łatwością zidentyfikować, przekazując wartość z pola tekstowego do narzędzia zajmującego się obsługą błędów. Aktywny formant zostanie przekazany do narzędzia zajmującego się obsługą błędów. Niektóre formanty posiadają wartości, inne nie. Narzędzie do obsługi błędów powinno przekazać ActiveControl (informację o aktywnym formancie) do procedury, która oceni jego wartość, używając do tego celu wbudowanej funkcji TypeOf. Jeśli formant jest polem tekstowym, otrzymasz wartość pola tekstowego. Jeśli jednak jest to przycisk poleceń, nie próbuj uzyskiwać jego wartości, bo spowoduje to powstanie błędu. ? Identyfikator bieżącego rekordu – przedstawia identyfikator (ID) rekordu, który był wyświetlany w formularzu w momencie wystąpienia błędu. Czy zdarzyło ci się zauważyć, że jeden, konkretny rekord klienta powoduje więcej błędów niż inne? Zapisując identyfikator bieżącego rekordu w narzędziu do obsługi błędów, będziesz mógł porównać ten rekord z innymi, które nie powodują powstawania błędów. Najczęstszym błędem jest brak wymaganych danych w którymś z pól. ? Nazwa programu – przedstawia nazwę aplikacji, w której wystąpił błąd. ? Poziom błędu – Możesz według własnego uznania przyznać błędom wartości (np. od 1 do 5). Dzięki tej informacji będzie można mierzyć konieczność korzystania z pomocy osoby zajmującej się serwisowaniem aplikacji. ? Nazwa użytkownika – nazwa aktualnie zalogowanego użytkownika. Zauważyłeś kiedyś, że większość błędów zdarza się określonym użytkownikom? Określenie, którzy użytkownicy mają najwięcej problemów, może być bardzo cenne. Wielokrotnie przekonasz się, że problemem nie są błędy w programie, lecz braki w wyszkoleniu pracowników. Aby otrzymać nazwę użytkownika, możesz użyć ekranu logowania, a w przypadku systemów Windows 95/98/NT nazwa zalogowanego użytkownika może być uzyskana przez odwołanie do interfejsu API systemu Windows. Przykład użycia odwołania do interfejsu API systemu Windows w celu otrzymania nazwy zalogowanego użytkownika w narzędziach do obsługi błędów znajduje się na dołączonej do książki płycie CD (właściwość UserName i funkcja GetUserName). ? Data i czas – Data i czas wystąpienia błędu. Informacja ta pomaga w analizowaniu częstotliwości występowania błędów. Prosty wykres powinien wystarczyć do wykazania, że z czasem błędy występują z mniejszą częstotliwością. ? Notatki o błędzie – Użytkownicy mogą wprowadzać informacje o tym, co robili w momencie wystąpienia błędu. Informacje te mogą być wprowadzane w polu tekstowym lub formularzu. Poinformuj użytkowników, że podanie tych informacji nie jest obowiązkowe. Część z nich nigdy nie sporządzi żadnej notatki o błędzie, lecz inni docenią możliwość udzielenia Ci informacji. Dzięki informacjom zdobytym dzięki obiektowi Err oraz innym, opisanym tu sposobom, programiści powinni mieć wystarczające podstawy do szybkiego i skutecznego naprawienia błędów wykrytych w trakcie użytkowania. Zaawansowane narzędzie do obsługi błędów Teraz, gdy wiesz już jak zbudować narzędzie do obsługi błędów na poziomie procedury i jak pobierać informacje o błędzie, nadszedł czas na stworzenie zaawansowanego narzędzia do obsługi błędów. Na początku musisz zdecydować, jak to narzędzie zaprojektować i gdzie umieścić kod. Można umieścić cały kod narzędzia w każdej procedurze, jednakże w ten sposób stworzyłbyś całą masę zbędnego kodu. Nie bez znaczenia byłby fakt, że modyfikując później narzędzie, musiałbyś dokonywać zmian w każdej procedurze. Przyjrzyj się umieszczonym na płycie CD narzędziom do obsługi błędów na poziomie procedury. Mimo iż użycie ogólnego narzędzia jest bardziej wydajne, jeśli nie masz doświadczenia z takimi narzędziami, powinieneś zapoznać się również z najbardziej podstawowymi przykładami. Lepszym podejściem jest użycie ogólnego narzędzia do obsługi błędów dla całej aplikacji. Ogólne narzędzie do obsługi błędów jest obiektem tworzonym przy użyciu modułu klasy. Idąc jeszcze dalej, możesz użyć Visual Basica do stworzenia narzędzia do obsługi błędów, które będzie mogło być używane w każdej aplikacji zgodnej z modelem COM (Compliant Object Model). Narzędzie takie mogłoby być wykorzystywane do wychwytywania błędów w Accessie, Wordzie, Excelu i wielu innych aplikacjach. Więcej informacji na ten temat znajdziesz w rozdziale 19., „Integracja z Office 2000”. Moduł klasowy Error (Obiekt) Znajdujący się w kodzie tego rozdziału moduł klasowy cError zawiera właściwości i metody niezbędne do stworzenia skutecznego narzędzia do obsługi błędów. Obiekt cError zawiera w module klasy całość kodu, który będziesz mógł teraz wykorzystać. Dzięki technologii IntelliSense, użycie tego obiektu jest dość łatwe. Jeśli nie miałeś okazji pracować jeszcze z modułami klasy, zajrzyj do rozdziału 11., Tworzenie obiektów przy użyciu modułów klasowych”. Właściwości obiektu cError Obiekt cError posiada właściwości umożliwiające przechwycenie żądanych wartości przez narzędzie do obsługi błędów. Właściwości te zostały opisane w tabeli 13.1. Tabela 13.1. Właściwości obiektu cError Właściwość Opis Application Nazwa programu, w którym została stworzona dana aplikacja (np. MS Access) AVIFileLocation Nazwa i pełna ścieżka dostępu do pliku AVI, który został odtworzony przy powiadomieniu o błędzie Class Nazwa modułu klasy ComputerName Nazwa komputera, na którym wystąpił błąd ComputerTotalMemory Całkowita pamięć tego komputera ComputerAvailableMemory Dostępna pamięć tego komputera ComputerOperatingSystem System operacyjny i informacje o wersji ComputerProcessor Informacje o procesorze ControlName Nazwa aktywnego formantu ControlValue Wartość aktywnego formantu CurrentRecordID Identyfikator bieżącego rekordu Description Opis błędu zwrócony przez obiekt cError EmailAdress Adres e-mail użyty do powiadomienia o błędzie ErrorDatabase Nazwa i pełna ścieżka dostępu do bazy danych (np. Accessa lub SQL Server) zawierającej tabelę z błędami ErrorNumber Numer błędu zwrócony przez obiekt cError ErrorTextFile Nazwa i pełna ścieżka dostępu do pliku tekstowego, zawierającego informacje o błędzie HelpContext Identyfikator pliku pomocy zwrócony przez obiekt cError HelpFile Nazwa i pełna ścieżka dostępu do pliku pomocy zwrócona przez obiekt cError LastDllError Systemowy kod błędu dla ostatniego odwołania do bibliotek DLL Level Ustalona wartość oznaczająca wagę błędu LineNumber Numer linii procedury, w której wystąpił błąd Tabela 13.1. Właściwości obiektu cError (ciąg dalszy) Właściwość Opis Note Notatka sporządzona przez użytkownika, opisująca co robił w momencie wystąpienia błędu Now Data i czas wystąpienia błędu Procedure Nazwa procedury, w której wystąpił błąd SoundFile Nazwa i pełna ścieżka dostępu do pliku dźwiękowego Source Nazwa obiektu lub aplikacji, która wywołała błąd User Nazwa użytkownika, który natrafił na błąd WaitStateFlag Znacznik stanu oczekiwania, używany do wstrzymania wykonywania kodu UserEnterNoteFlag Znacznik stwierdzający, czy użytkownik ma być proszony o sporządzenie notatki o błędzie W momencie powstania błędu, ustawiana jest większość, jeśli nie wszystkie z tych właściwości. Wówczas można pobrać te informacje z obiektu cError i umieścić je w oknie komunikatu, e-mailu, kalendarzu, tabeli w bazie danych lub pliku tekstowym. Metody obiektu cError Metody obiektu cError dostarczają programiście użytecznych informacji o błędach. Przykładowo, informacje o błędach mogą być przesyłane do programisty pocztą elektroniczną lub zapisywane w bazie danych. Metody obiektu cError opisane są w tabeli 13.2. Tabela 13.2. Metody obiektu cError Metoda Opis AddToErrorHandlerOutlook Calendar Dodaj informacje o błędzie do kalendarza programu Outlook, o nazwie ErrorHandler Clear Czyści obiekt cError Email W przypadku wystąpienia błędu, korzystając z programu Outlook, wysyła programiście e-mail EmailAllErrors Wysyła programiście e-mail, w którego załączniku znajdują się wszystkie informacje z tabeli z błędami GetActiveControlValue Pobiera wartość formantu aktywnego w momencie wystąpienia błędu MessageBox Wyświetla użytkownikom okno komunikatu z informacjami o błędzie MsgErrorDetails Grupuje informacje o błędzie, w celu umieszczenia ich w oknie komunikatu lub e-mailu Tabela 13.2. Metody obiektu cError (ciąg dalszy) Metoda Opis OfficeAssistant W momencie wystąpienia błędu uruchamia Asystenta Pakietu Office i pyta użytkowników, czy chcą sporządzić notatkę o błędzie PlaySound W celu zwrócenia uwagi użytkowników w momencie wystąpienia błędu odtwarza plik dźwiękowy ProcessError Nadzoruje przetwarzanie informacji o błędzie na podstawie wcześniej ustalonych zasad ShowAVIForm Wyświetla formularz zawierający plik AVI, który informuje użytkowników o wystąpieniu błędu UserInputBox Wyświetla okno, w którym użytkownicy mogą wprowadzić swoje uwagi o błędzie UserName W systemach Windows, Windows NT pobiera nazwę zalogowanego użytkownika WaitState Przechodzi w stan oczekiwania i wstrzymuje wykonywanie kodu WriteErrorToTable Zapisuje informacje o błędzie do odpowiedniej tabeli w bazie danych WriteErrorToTextFile Zapisuje informacje o błędzie do pliku tekstowego Przeglądanie obiektu cError w Object Browser Jak pewnie zauważyłeś, obiekt cError posiada wiele właściwości i metod. Aby je przejrzeć, otwórz Object Browser i wybierz moduł klasy cError (rysunek 13.4). Rysunek 13.4. Obiekt cError widziany w Object Browser Przetwarzanie błędu W momencie wystąpienia błędu, narzędzie do obsługi błędów przekazuje informacje do obiektu cError. Metoda ProcessError określa sposób przetwarzania błędu. Odwołuje się do tabeli tblErrorOptions (tabela ta opisana jest w dalszej części rozdziału) w celu uzyskania informacji o tym, czy użytkownik ma sporządzać notatkę o błędzie lub czy zostanie wysłany e-mail powiadamiający. Kod w metodzie ProcessError jest następujący: Public Sub ProcessError() Dim rst As ADODB.Recordset Dim strSQL As String Dim strVal As String strSQL = "SELECT * FROM tblErrorOptions" ' Utwórz zestaw rekordów ADO Set rst = New ADODB.Recordset ' Otwórz zestaw rekordów ADO rst.Open strSQL, CurrentProject.Connection, adOpenKeyset, _ adLockOptimistic Me.ErrorTextFile = rst!ErrorTextFileName Me.UserEnterNoteFlag = rst!UserEnterNoteAboutError Me.AVIFileLocation = CurrentProject.Path & rst!AVIFileLocation Me.SoundFile = CurrentProject.Path & rst!SoundFile Me.OfficeID = rst!OfficeID Me.OfficeName = rst!OfficeName Me.OfficePhoneNumber = rst!OfficePhoneNumber Me.OfficeFaxNumber = rst!OfficeFaxNumber If rst!PlaySound Then ' W razie wystąpienia błędu odtwórz dźwięk CError.PlaySound End If If rst!ShowOfficeAssistant Then ' Uruchom Asystenta Pakietu Office CError.OfficeAssistant End If If rst!ShowAVIForm Then ' Otwórz formularz z plikiem AVI CError.ShowAVIForm ' Wstrzymaj wykonywanie kodu do zamknięcia formularza Me.WaitState (True) 'Zamknij formularz AVI DoCmd.Close acForm, "frmErrorAVI", acSaveNo End If ' Otwórz formularz, w którym użytkownik będzie mógł ' sporządzić notatkę If Me.UserEnterNoteFlag Then DoCmd.OpenForm "frmErrorNote", acNormal ' Wstrzymaj wykonywanie kodu do zamknięcia formularza Me.WaitState (True) ' Zamknij formularz z notatką DoCmd.Close acForm, "frmErrorNote", acSaveNo End If If rst!ErrorsToAccessTable Then ' Zapisz błąd w tabeli błędów Accessa CError.WriteErrorToTable End If If rst!ErrorsToTextFile Then ' Zapisz błąd w pliku tekstowym CError.WriteErrorToTextFile End If If rst!ErrorsToTextFile Then ' Zapisz błąd w pliku tekstowym CError.WriteErrorToTextFile End If If rst!AddToErrorHandlerCalendar Then CError.AddToErrorHandlerOutlookCalendar End If If rst!ShowMsgBoxErrors Then ' Wyświetl okno komunikatu z informacją o błędzie CError.MessageBox End If ' Wyświetl formularz z informacją, że użytkownik ' może kontynuować pracę. Formularz zostanie automatycznie ' zamknięty ' po upływie określonego czasu. DoCmd.OpenForm "frmErrorDone", acNormal rst.Close Set rst = Nothing End Sub Jak widzisz, metoda ta może opierać się zarówno na właściwościach, jak i innych metodach obiektu cErrror. Więcej informacji znajdziesz w kodzie modułu klasy cError. Doświadczenie użytkownika końcowego Jak powinna wyglądać obsługa błędów z punktu widzenia użytkownika końcowego? Po pierwsze, należy przyciągnąć jego uwagę tak, by przestał pracować. Pamiętaj, że błąd może być bardzo poważny i spowodować, na przykład, wprowadzenie do bazy niewłaściwych danych. Dzięki odwołaniu do metod obiektu cError wyświetlony zostanie Asystent Pakietu Office oraz formularz z plikiem AVI, odtworzony zostanie również sygnał dźwiękowy, informujący o wystąpieniu błędu (rysunek 13.5). Znajdujący się na płycie CD przykład kodu zawiera również formularz AVI, powiadamiający użytkownika o błędzie (rysunek 13.6). Wywołanie takich zdarzeń przy użyciu modułu klasy cError jest bardzo proste: cError.OfficeAssistant cError.AVIForm cError.Sound Rysunek 13.5. Asystent pakietu Office informuje użytkownika o wystąpieniu błędu Rysunek 13.6. Formularz z plikiem AVI informuje o wystąpieniu błędu Wówczas możesz użyć obiektu cError do wyświetlenia formularza lub pola, które umożliwią użytkownikom opisanie czynności, wykonywane w momencie wystąpienia błędu (rysunek 13.7). Niektórzy użytkownicy docenią taką możliwość, inni po prostu ominą ten krok. Formularz z notatką zawiera informację, że sporządzanie jej nie jest obowiązkowe. Rysunek 13.7. Formularz umożliwiający użytkownikom sporządzenie notatki o błędzie Można również wyświetlić okno komunikatu zawierające szczegółowe informacje o błędzie (rysunek 13.8). Ostatni krok to wyświetlenie informacji o tym, że błąd został zapisany i można bezpiecznie kontynuować pracę (rysunek 13.9). Służy do tego formularz, który zamknie się automatycznie po trzech sekundach. Dzięki tym wszystkim działaniom użytkownicy są przez cały czas wspomagani – nie są po prostu brutalnie wyrzuceni z aplikacji. Narzędzie do obsługi błędów umożliwi kontynuowanie wykonywania kodu i aplikacja będzie działać nadal. Użytkownicy będą natychmiast poinformowani o błędzie i będą mieli możliwość przekazania własnych spostrzeżeń. A co najważniejsze, użytkownicy mają pewność, że informacja o wystąpieniu błędu została przekazana do programisty i że mogą kontynuować pracę. Dzięki takiej obsłudze błędów użytkownicy będą przekonani o profesjonalizmie Twojej aplikacji. Rysunek 13.8. Okno komunikatu ze szczegółowymi informacjami o błędzie Rysunek 13.9. Poinformuj użytkownika, że może bezpiecznie kontynuować pracę Identyfikowanie problemów sprzętowych Czy zdarzyło Ci się kiedyś zauważyć, że niektóre komputery w biurze ciągle generują błędy? Jest to chyba najtrudniejszy problem do rozwiązania. Problem może być związany ze sprzętem, jego konfiguracją, konfliktem z innymi aplikacjami itp. Zauważ, że narzędzie do obsługi błędów radzi sobie z tym na kilka sposobów. Obiekt cError posiada właściwości (tabela 13.1), które umożliwiają przechwycenie nazwy komputera, całkowitej i dostępnej wielkości pamięci, systemu operacyjnego i typu procesora. Wszystkie te informacje mogą być przydatne we wskazaniu, dlaczego dany komputer sprawia problemy. Podczas gdy inne działają poprawnie. Najczęstszym problemem jest pamięć, dlatego też w razie wystąpienia błędu zwracaj uwagę na informacje o całkowitej i dostępnej ilości pamięci. Sporządzanie raportów o błędach Gdy już wiesz, jak narzędzie do obsługi błędów odbierane jest przez użytkowników, zobaczmy, co daje programiście, czyli Tobie. Dzięki obiektowi cError możesz kompilować i analizować błędy programowe na kilka sposobów: ? Raport o błędach – raport o błędach to raport Accessa zawierający informacje z tabeli, w której są zapisane wszystkie błędy (rysunek 13.10). ? Wysyłanie e-maili o pojedynczych błędach – za każdym razem gdy występuje błąd, związane z nim szczegóły przesyłane są do Ciebie pocztą elektroniczną przy użyciu metody E-mail (rysunek 13.11). Rysunek 13.10. Raport Accessa zawierający informacje o błędach Rysunek 13.11. E-mail zawierający informację o pojedynczym błędzie ? Wysyłanie e-maila o wszystkich błędach – przy użyciu metody EmailAllErrors informacje o wszystkich błędach z tabeli z błędami mogą być przesyłane do Ciebie pocztą elektroniczną jako załącznik wiadomości programu Outlook. Tabela ta zapisywana jest jako arkusz programu Excel i załączana do wiadomości. ? Zapisywanie informacji o błędzie w bazie danych Accessa – dzięki użyciu metody WriteErrorToTable każdy błąd dodawany jest do tabeli w bazie danych. ? Zapisywanie informacji o błędzie w pliku tekstowym – dzięki użyciu metody WriteErrorToTextFile wszystkie błędy będą zapisywane w wybranym pliku tekstowym. ? Zapisywanie informacji o błędzie w kalendarzu programu Outlook – informacje o błędach mogą być zapisywane w kalendarzu programu Outlook i przeglądane w różnych, zarówno wbudowanych jak i własnych, widokach. Dzięki użyciu metody AddToErrorHandlerOutlookCalendar informacje o błędach przesyłane są do odpowiedniego kalendarza (rysunek 13.12). Rysunek 13.12. Kalendarz programu Outlook, zawierający informacje o błędach Używając jednej lub kilku metod raportowania, otrzymujesz natychmiastowe powiadomienia o występowaniu błędów. Posiadasz również wszystkie informacje niezbędne do odnalezienia i naprawienia błędu oraz narzędzia umożliwiające analizę historyczną. Opcje obiektu cError Jak widzisz, rozbudowane narzędzie do obsługi błędów zawiera wiele opcji i możliwości. Niektórzy Twoi klienci będą chcieli wykorzystać je wszystkie, inni nie. Wszystkie opcje tego narzędzia znajdują się w tabeli tblErrorOptions. Tabela 13.3. Możliwości dostępne w module obsługi błędów Opcja Opis Typ danych AccessErrorTableName Nazwa tabeli Accessa zawierającej informacje o błędzie Tak/Nie AddToErrorHandlerCalendar Dodawanie błędu do kalendarza programu Outlook Tak/Nie AVIFileLocation Pełna ścieżka dostępu do pliku AVI odtwarzanego w formularzu AVI Tekst DatabaseName Nazwa bazy danych, w której znajduje się tabela z informacjami o błędach Tekst DatabasePath Pełna ścieżka dostępu do wspomnianej bazy danych Tekst EmailAdress Adres e-mail, na który mają być wysyłane informacje o błędach Tekst Tabela 13.3. Możliwości dostępne w module obsługi błędów (ciąg dalszy) Opcja Opis Typ danych EmailErrors Powiadamianie o błędach za pomocą poczty elektronicznej Tak/Nie ErrorsToAccessTable Zapisywanie informacji o błędzie w tabeli Accessa Tekst ErrorsToTextFile Zapisywanie informacji o błędzie w pliku tekstowym Tekst PlaySound Odtwarzanie dźwięku w przypadku wystąpienia błędu Tak/Nie ShowAVIForm Otwieranie formularza z plikiem AVI w przypadku wystąpienia błędu Tak/Nie ShowMsgBoxerrors Wyświetlanie okna komunikatu z informacją o błędzie Tak/Nie ShowOfficeAssistant Uruchamianie Asystenta Pakietu Office w przypadku wystąpienia błędu Tak/Nie SoundFile Pełna ścieżka dostępu do pliku dźwiękowego Tekst UserEnterNoteAboutError Umożliwienie użytkownikowi sporządzenia notatki o błędzie Tak/Nie W zależności od wybranych opcji narzędzie do obsługi błędów będzie funkcjonować inaczej. Do przechowywania informacji o opcjach obiektu cError służy tabela, więc kod aplikacji może być od niej zależny. Zamiast umieszczać wartości nowych opcji w kodzie, możesz je po prostu wprowadzić do tabeli z opcjami. Jest to dużo prostsze rozwiązanie, gdyż kod sam odnajdzie w tej tabeli potrzebne informacje. Oczywiście nie należy kazać użytkownikom wprowadzać danych prosto do tabeli. Łatwe aktualizowanie i zmienianie opcji związanych z błędami umożliwia formularz frmErrorOptions (rysunek 13.13). Rysunek 13.13. Formularz, z poziomu którego można modyfikować opcje związane z obsługą błędów W tym momencie, masz już nie tylko zaawansowane narzędzie do obsługi błędów, ale co równie ważne, narzędzie, które jest przyjazne i łatwe w obsłudze. Odwołania do interfejsu API systemu Windows Pełen zestaw funkcji, jakie powinno posiadać zaawansowane narzędzie do obsługi błędów, nie byłby możliwy do osiągnięcia bez kilku odwołań do interfejsu API systemu Windows. Narzędzie do obsługi błędów otrzymuje nazwę użytkownika, który napotkał błąd. Zamiast prosić użytkownika o podanie swojej nazwy, narzędzie pobiera ją z interfejsu API. Odwołanie do interfejsu API systemu w systemach Windows 95/98/NT wygląda następująco: ' Odwołanie do interfejsu API systemu Windows w celu pobrania nazwy użytkownika. Private Declare Function GetUserNAme Lib "advapi32.dll" _ Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) W momencie wystąpienia błędu może być odtwarzany wybrany dźwięk, który zaalarmuje użytkowników. Do tego potrzebne jest również odwołanie do interfejsu API: ' Odwołanie do interfejsu API systemu Windows w celu ' odtworzenia dźwięku. Private Declare Function sndPlaySound32 Lib "winmm.dll" Alias _ "sndPlaySoundA" (ByVal lpszSoundName As String, _ ByVal uFlags As Long) As Long Inne odwołania do interfejsu API mogą służyć do pobierania nazwy komputera, informacji o stanie pamięci, systemie operacyjnym i procesorze. Błędy w różnych aplikacjach Współczesne aplikacje Accessa zawierają w sobie inne aplikacje i komponenty. Stąd też, błędy mogą pochodzić z wielu źródeł. W typowej aplikacji Accessa mogą występować błędy związane z samym Accessem, VBA, DAO, ADO lub innymi aplikacjami (np. Word). Każda aplikacja posiada własne kody błędów, które mogą być zapisywane przez narzędzie do obsługi błędów. Przejrzyj znajdującą się na płycie CD bazę danych Access and Jet database Errors.mdb. Zawiera ona numer i opisy błędów baz danych Accessa i Jet. Obsługa błędów w procedurach zagnieżdżonych Często w kodzie możesz mieć procedury, które odwołują się do innych procedur, które odwołują się do jeszcze innych procedur itd. Jak radzić sobie z obsługą błędów w takich przypadkach? Służy do tego tworzona automatycznie lista zawierająca wszystkie odwołania do procedur (rysunek 13.14). Możesz przeglądać tę listę w dowolnym momencie, wybierając z menu Tools Edytora Visual Basic pozycję Call Stack. Rysunek 13.14. Okno Call Stack W momencie wystąpienia błędu jego obsługą zajmuje się narzędzie zawarte w bieżącej procedurze. Jeśli jednak w tej procedurze takie narzędzie nie istnieje, obsługa błędu spadnie na narzędzie z procedury, z której nastąpiło odwołanie. Innymi słowy, VBA będzie przeszukiwać listę odwołań, aż znajdzie narzędzie do obsługi błędów. Zwróć uwagę na zagrożenia związane z następującym scenariuszem: obsługą błędu zajmuje się niewłaściwe narzędzie. Przeznaczone było do obsługi zupełnie innej instrukcji kodu, w zupełnie innej procedurze niż ta, w której wystąpił błąd. Stąd też rzeczą podstawową jest umieszczanie narzędzia do obsługi błędów w każdej procedurze. Zaawansowane zagadnienia związane z błędami Teraz, gdy już wiesz jak radzić sobie z błędami składni, logicznymi oraz błędami związanymi z użytkowaniem aplikacji, przyjrzyj się bardziej zaawansowanym kwestiom związanym z obsługą błędów. Procedury zdarzeń związane z błędami Formularze i raporty w Accessie posiadają zdarzenia Przy błędzie, które można wykorzystać do wyświetlenia dowolnej wiadomości w razie wystąpienia błędu. Procedura tego zdarzenia posiada dwa argumenty: ? DataErr – numer błędu zwracany przez obiekt Err. Używając tego argumentu, możesz reagować na określone typy błędów. Jeśli, przykładowo, DataErr jest równe 11, wystąpił błąd dzielenia przez zero. ? Response – określa, czy komunikat o błędzie jest wyświetlany. Argument ten możesz wykorzystać do określenia sposobu powiadomienia o błędzie. Aby zignorować błąd i wyświetlić własny komunikat o błędzie, użyj stałej acDataErrContinue. Aby wyświetlić standardowy komunikat Accessa, użyj stałej acDataErrDisplay. Typowy fragment kodu wyglądałby następująco: Private Sub Form_error(DataErr As Integer, Response As Integer) Dim strMessage As String If DataErr = 11 Then Response = acDataErrContinue StrMessage = "Sprawdź wartość, wykonałeś dzielenie przez zero" MsgBox strMessage End If End Sub On Error GoTo 0 Powyższa instrukcja wyłącza obsługę błędów w procedurze. Powoduje to również wyzerowanie obiektu Err (tak jak w przypadku użycia metody Clear obiektu Err (Err.Clear)). Metoda Err.Clear została opisana w jednym z wcześniejszych rozdziałów książki. On Error Resume Next Nie używaj instrukcji On Error Resume Next, gdy nie posiadasz żadnego narzędzia do obsługi błędów. W takim przypadku, wykonywanie kodu będzie kontynuowane, a wszystkie błędy będą ignorowane. Może to mieć katastrofalne konsekwencje. Przykładowo, w momencie wystąpienia błędu, który powoduje utratę danych w bazie, ta instrukcja nakaże kontynuację wykonywania kodu! Metoda AccessError Metoda ta może być użyta do zwrócenia opisu błędu Accessa. Przykładowo, wpisując ?AccessError(11) w oknie Immediate otrzymamy Division by zero (Dzielenie przez zero). Rysunek 13.15. Użycie metody AccessError w oknie Immediate Inne funkcje związane z błędami Poniższe dwie funkcje mogą być bardzo użyteczne: ? IsError – funkcja służąca do określenie, czy zmienna związana z błędem ma wariantowy typ danych (Variant). Funkcja ta zwraca wartość logiczną. ? CVError – konwertuje wartość zmiennej związanej z błędem na zmienną wariantową. Ustawienie opcji wyłapujących błędy W Edytorze Visual Basic, z menu Tools wybierz Options. Na zakładce General znajdziesz opcje regulujące obsługę błędów przez Access (rysunek 13.16): Rysunek 13.16. Ustawienia opcji wyłapujących błędy ? Break on All Errors – w momencie wystąpienia błędu kod zatrzymuje się w danej linii, niezależnie od istnienia narzędzia do obsługi błędów. Opcja ta jest dobra w momencie usuwania błędów aplikacji, pamiętaj jednak, by ją wyłączyć, przekazując aplikację użytkownikom. ? Break in Class Module – w momencie wystąpienia błędu kod zatrzymuje się w danej linii jedynie w przypadku modułów klasy, przy braku narzędzia do obsługi błędów. ? Break on Unhandled Errors – w momencie wystąpienia błędu kod zatrzymuje się w danej linii w każdej procedurze, nie zawierającej narzędzia do obsługi błędów. Możesz wyłączyć ustawienie Break on All Errors w procedurze, umieszczając u jej góry następujący kod: Application.SetOption "Break On All Errors", False Rozdział 14. Optymalizacja aplikacji W tym rozdziale: ? Ulepszanie podstaw: optymalizacja sprzętu i systemu Windows. ? Instalowanie aplikacji w celu uzyskania optymalnej wydajności. ? Optymalizacja silnika bazy danych Jet. ? Narzędzia do pomiaru wydajności. ? Spojrzenie za kulisy. ? Optymalizacja bazy danych od podstaw. ? Poprawa wydajności kwerend. ? Zwiększenie szybkości kwerend. ? Przyspieszenie funkcjonowania formularzy. ? Pisanie szybkiego kodu. Optymalizacja aplikacji jest tematem niekończącej się dyskusji między programistami. Każdemu zależy na osiągnięciu optymalnego rozwiązania, lecz co w tym przypadku jest rozwiązaniem optymalnym? Jedni uważają za takie dużą szybkość aplikacji, więc dla nich najlepszymi technikami są najszybsze z nich. Inni uważają, że optymalne rozwiązanie powinno zapewniać jak największą stabilność aplikacji, nawet za cenę zmniejszonej przez przesadną ostrożność szybkości działania. Jeszcze inni za cel optymalny uważają jak największą elastyczność i łatwość w obsłudze. Kto ma rację? Jak to często w życiu bywa, żaden z nich. Optymalizacja polega na znalezieniu równowagi pomiędzy tymi trzema celami. Rozwiązanie optymalne zapewnia użytkownikowi odpowiednią szybkość. Zazwyczaj użytkownik nie zaakceptuje zbyt wolnej aplikacji. Jeśli jednak okaże się, że wybór tego rozwiązania prowadzi do utraty danych, będzie niewątpliwie wyborem złym. Jeśli aplikacja działa z zadowalającą szybkością i do tego jest stabilna, istnieje duże prawdopodobieństwo, że jej użytkownicy będą zainteresowani jej kolejnymi wersjami. Jednakże niekonwencjonalne rozwiązania w projekcie i nieortodoksyjne jego wykonanie mogą sprawić, że dobrze przyjęta aplikacja będzie trudna do ulepszenia i rozbudowania. Pod pewnymi względami, aplikacje są jak samochody. Niewiele osób chciałoby znaleźć się za kierownicą bardzo szybkiego samochodu, który źle się prowadzi lub ma słabe hamulce. Natomiast większość z nas życzyłaby sobie mieć samochód, który zapali każdego dnia i zawiezie nas tam, gdzie chcemy. Nie zapominajmy też o tym, że rachunki za serwisowanie tego samochodu nie powinny rujnować naszego budżetu. Mimo iż rozdział ten dotyczy optymalizacji, pamiętaj o tym, że aplikacja powinna być również stabilna i łatwa w rozbudowie. W rozdziale tym omówimy wiele technik służących optymalizacji aplikacji. Prawie wszystkie z nich mają jakieś ograniczenia, a niektóre mogą wręcz spowodować efekty odwrotne do zamierzonych. Nawet najlepsze z nich mogą nie nadawać się do rozwiązania jakiegoś konkretnego problemu. Kilka technik zastosowanych razem może wzajemnie pomniejszać efekty swojego działania. Jednakże z rozwagą stosując to, czego nauczy Cię lektura tego rozdziału, powinieneś umieć poprawić wydajność swoich aplikacji. Jedynym sposobem na sprawdzenie, czy techniki te będą działać w danym przypadku, jest eksperymentowanie. Rezultaty mogą być często zaskakujące. Jednocześnie metoda, która w jednym przypadku dała zdumiewające rezultaty, w innym może nie dać żadnych. Optymalizacja jest bardzo złożonym procesem, gdyż środowisko, w którym pracujemy, jest bardzo złożone i podlega ciągłym zmianom, a prawdziwy cel optymalizacji jest dość trudny do zdefiniowania. Pisząc o optymalizacji, należałoby omówić setki zagadnień. W rozdziale tym zaczniemy od omówienia problemów związanych ze sprzętem i systemem operacyjnym, a zakończymy na różnych technikach kodowania. Ulepszanie podstaw: optymalizacja sprzętu i systemu Windows Każdy element Accessa posiada wiele możliwości poprawienia wydajności aplikacji, lecz żaden z nich nie zda się na zbyt wiele, jeśli aplikacja będzie działać na przestarzałym komputerze, ze zbyt mała ilością pamięci. Zazwyczaj tańszym rozwiązaniem jest zakup sprzętu niż zapłacenie firmie programistycznej za osiągnięcie tego samego rezultatu. Sprzęt jest tańszy niż oprogramowanie, a modyfikacje sprzętowe poprawiają funkcjonowanie wszystkich aplikacji uruchamianych na danym komputerze. Nie powinno nikogo dziwić, że aplikacja Accessa (lub jakakolwiek inna) będzie działać szybciej na szybszym komputerze. Jeśli masz możliwość poprawy szybkości komputera, na którym będzie uruchamiana aplikacja, zrób to. Opublikowane przez Microsoft minimalne wymagania potrzebne do uruchomienia Accessa lub pakietu Office są niczym innym jak właśnie minimalnymi wymaganiami. Programiści szybko przekonają się, że uruchomienie aplikacji Access na takim komputerze będzie miało marny efekt. Tak naprawdę, komputer taki powinien spełniać co najmniej poniższe wymagania: ? Procesor Pentium 133 MHz. ? 32 MB RAM (szczególnie w przypadku systemu Windows NT). ? Jeśli masz wybierać między szybszym procesorem a większą ilością pamięci, wybierz pamięć. Jest to najtańszy sposób na poprawę wydajności komputera. Pamiętaj również, że minimalne wymagania dla komputera, na którym tworzy się aplikacje ,są dużo wyższe. Programista powinien dysponować komputerem, który posiada między innymi procesor minimum Pentium 200 MHz oraz 32 – 64 MB RAM. ? Niezależnie od ilości posiadanej pamięci RAM, zawsze istnieje możliwość jej wykorzystania. Access, jak każda poważna baza danych, do poprawnego funkcjonowania potrzebuje dużo pamięci. Powinieneś podjąć kroki w celu zapewnienia aplikacji możliwie jak największej ilości pamięci. ? Aby to osiągnąć, usuń wygaszacze ekranu, tapety (chyba że jest to standardowa bitmapa), rysunki z tła i wszystko, co może być zbędne. Tylko niezbędne aplikacje mogą korzystać z procesora w trakcie działania bazy danych. Im więcej pamięci dostarczysz Accessowi, tym szybciej będzie działał. ? Nie używaj RAM-dysków. W nowoczesnych, 32-bitowych systemach nie ma na nie miejsca. ? Regularnie opróżniaj kosz i usuwaj pliki tymczasowe (szczególnie te, związane z Internetem i pocztą elektroniczną). Bazy danych potrzebują do funkcjonowania dużo przestrzeni dyskowej, a takie pliki mogą zajmować duże jej ilości. ? Korzystaj z narzędzi do defragmentacji dysków. W zależności od systemu operacyjnego, defragmentacja może być automatyczna lub nie. Pliki komputerowe nie są przechowywane w jednym kawałku. Gdy tworzysz, edytujesz, zapisujesz i usuwasz pliki, komputer rozdziela je i umieszcza w różnych miejscach. Tak samo jest z plikami baz danych. Jeśli twardy dysk jest sfragmentowany, nawet proste przeszukiwanie może trwać dłużej niż normalnie, gdyż komputer musi przeszukać cały dysk, by odnaleźć żądane fragmenty. ? Unikaj kompresji dysków (również kompresji NTFS). Uruchamianie bazy danych na skompresowanym dysku będzie miało znaczny, negatywny wpływ na wydajność aplikacji. ? Kup większy dysk twardy. W zależności od rozmiaru aplikacji, możesz potrzebować 5 do 10 razy więcej wolnego miejsca niż wynosi rozmiar pliku MDB. Brak wolnego miejsca spowoduje spadek wydajności dużych kwerend, spowolni transakcje, kompilację, obsługę, importowanie i działanie kwerend. W ostatnich latach ceny przestrzeni dyskowej znacznie spadły. ? Wyłącz dziennik programu Outlook. Opcja ta zapisuje każde otwarcie i zamknięcie aplikacji. Może to spowodować utratę cennej przestrzeni dyskowej i niepotrzebne obciążenie procesora. ? Odbieraj brakującą pamięć. Aplikacje bardzo łatwo zajmują pamięć, lecz gorzej jest z oddawaniem. Otwieranie wielu aplikacji, w tym Accessa, spowoduje zmniejszenie rzeczywistej, dostępnej ilości pamięci. Zamknięcie Accessa spowoduje odzyskanie tej pamięci. ? Instaluj system Windows i pakiet Office lokalnie. Nie uruchamiaj ich przez sieć. Wydaje się to dziwne, lecz wciąż istnieją miejsca, gdzie praktykuje się takie rozwiązania. ? Na poprawę wydajności aplikacji mogą również wpłynąć zmiany w pliku wymiany (pamięci wirtualnej). Gdy Accessowi zabraknie pamięci, zaczyna korzystać z wirtualnej pamięci na dysku twardym. Jeśli wirtualnej pamięci jest za mało, Access w celu wykonywania swoich operacji musi ciągle zapisywać i odczytywać informacje z dysku. Zwiększenie ilości pamięci wirtualnej może poprawić wydajność bazy danych. Pamiętaj jednak, ze zapisywanie i odczytywanie informacji z dysku jest znacznie wolniejsze niż korzystanie z pamięci RAM. Zwiększenie pliku wymiany ma sens tylko wtedy, gdy dysk jest zdefragmentowany. Upewnij się, ze plik wymiany nie znajduje się na skompresowanym dysku lub partycji. Kompresja znacznie spowolni odczytywanie i zapisywanie na dysku tymczasowych plików, które muszą być w tym miejscu zapisywane. Wiele z wyżej wymienionych kwestii może być poza Twoją kontrolą, lecz tworząc aplikację Accessa, powinieneś rozważyć je i w razie konieczności zaproponować. Jako projektant bazy danych Accessa masz większą kontrolę nad tym, czy korzystać z możliwości optymalizacji. Wielu programistów używa komputerów dużo szybszych niż te, na których będzie działać aplikacja. Pamiętaj, by przetestować aplikację na komputerach podobnych do tych, jakich używają przyszli użytkownicy. Jeśli konfiguracje sprzętowe komputerów użytkowników są różne, pisz aplikację pod kątem najsłabszego z nich. Instalowanie aplikacji w celu uzyskania optymalnej wydajności Sposób, w jaki skonfigurujesz pliki, z których aplikacja korzysta, może mieć wpływ na jej wydajność. Poniższe wskazówki powinny pomóc w osiągnięciu prawidłowego funkcjonowania aplikacji i umożliwić Ci skorzystanie z reszty tego rozdziału. ? Oddziel dane od aplikacji. Tworzenie pliku MDB z tabelami, umieszczanie go w sieci i instalowanie na komputerach użytkowników innego pliku MDB zawierającego kwerendy, formularze, raporty itp. powinno być standardem. Ma to również wpływ na wydajność, dostępność dla wielu użytkowników i łatwość obsługi aplikacji. Ze wszystkich zawartych w tym rozdziale sugestii tę powinieneś ignorować tylko z naprawdę ważnych przyczyn. ? Używaj aktualnej wersji pliku grupy roboczej (system.mdw). Mimo iż możliwe jest użycie wcześniejszych wersji pliku grupy roboczej w aplikacji, użycie aktualnej wersji powinno dać największą wydajność. ? Zmniejszaj bazę danych regularnie. Powinieneś kompaktować bazę za każdym razem, gdy importujesz, usuwasz lub aktualizujesz większe ilości danych. Kompaktowanie bazy danych powoduje usunięcie pustych miejsc między stronami danych i ponowne przeliczenie statystyk bazy, używanych w optymalizacji kwerend (więcej na ten temat w dalszej części rozdziału). Proces ten powoduje również zwolnienie części przestrzeni dyskowej dla innych procesów. Access 2000 posiada opcję kompaktowania bazy danych przy jej zamykaniu. Z menu Narzędzia wybierz Opcje i na zakładce Ogólne zaznacz pole Kompaktuj przy zamknięciu. Niektórzy programiści zauważyli, że we wcześniejszych wersjach Accessa kompaktowanie odnosiło rezultaty tylko wtedy, gdy było wykonywane dwukrotnie. Spróbuj kompaktować swoją bazę przy uruchamianiu, a dzięki zaznaczeniu opcji Kompaktuj przy zamknięciu, będzie ona zawsze kompaktowana dwukrotnie. ? Gdy tylko jest to możliwe, instaluj wersję MDE swojej aplikacji. Rozwiązanie to posiada kilka zalet. MDE wymaga skompilowanych modułów, a moduły takie działają szybciej niż nieskompilowane. MDE daje większą wydajność przy mniejszym zapotrzebowaniu na RAM i przestrzeń dyskową. Przed zainstalowaniem MDE upewnij się, że użytkownicy wiedzą, iż żaden z nich nie będzie w stanie modyfikować aplikacji w tej formie. Ze względu na dużą popularność Accessa wielu użytkowników chce mieć możliwość dokonywania późniejszych modyfikacji w aplikacji. Powinieneś również bardzo dokładnie przetestować taką aplikację, gdyż komunikaty o błędach MDE są bardzo trudno zrozumiałe. Optymalizacja silnika bazy danych Jet Dobrze skonfigurowany komputer i zoptymalizowana instalacja nie dadzą zbyt dużych rezultatów, jeśli nie zoptymalizujesz samej aplikacji. Aplikacja bazy danych składa się z kilku elementów. Najważniejszym z nich jest silnik baz danych Jet. Jet znajduje się w centrum prawie wszystkich procesów zachodzących w aplikacjach Accessa i można go optymalizować tak jak inne elementy baz danych. Optymalizację silnika Jet powinieneś zacząć dopiero po ukończeniu całej lub prawie całej aplikacji i po rozważeniu różnych technik optymalizacyjnych wewnątrz aplikacji. Jet 4.0, silnik baz danych Accessa 2000, posiada kilka zalet odróżniających go od wcześniejszych wersji. Takie opcje, jak: nowe typy danych, kompresja tekstu, indeksowanie pól memo, implementacja ANSI SQL-92, zarządzanie zabezpieczeniami, zwiększona elastyczność dzięki indeksom klucza obcego, znacznie poszerzony schemat replikacji i poprawione blokowanie, wpływają na znaczną poprawę wydajności aplikacji. Opcje te zostały w pełni opisane w innych rozdziałach tej książki. Powinieneś je przejrzeć, by dowiedzieć się więcej o tych ważnych opcjach. Teraz zajmiemy się jedynie ich wpływem na wydajność aplikacji. Jet zajmuje się większością kwestii związanych z optymalizacją, bez żadnej interwencji programisty czy użytkownika. Ze wszystkich czynności, jakie Jet wykonuje, około 15 z nich możesz zobaczyć w rejestrze. Ich ustawienia nie są zbyt oczywiste i powinieneś podejść do nich z ostrożnością. Zmiana tych ustawień może przynieść efekt odwrotny do zamierzonego. Nawet, jeśli aplikacja będzie działać szybciej, może mieć negatywny wpływ na inne ważne rzeczy, jak stabilność czy zarządzanie współbieżnością. Lista dostępnych ustawień rejestru silnika Jet znajduje się w tabeli 14.1. Tabela 14.1 Ustawienia rejestru dla silnika Jet 4.0 Klucz Opis Wartość Domyślna Miejsce Klucza Stała dla metody SetOption ExclusiveAsyncDelay Liczba milisekund, jakie Jet musi odczekać przed wykonaniem ukrytej transakcji w środowisku z wyłącznością 2000 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET\4.0\ENGINES\JET4.0 dbExclusive AsyncDelay FlushTransactionTimeout Gdy w tym miejscu wprowadzona jest wartość, wyłączone są SharedAsyncDelay i ExclusiveAsyncDelay.Wartość ta określa liczbę milisekund do rozpoczęcia zapisywania asynchronicznego, bez dodawania stron do bufora 500 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbFlush Transaction Timeout ImplicitCommitSync Określa, czy system ma czekać na zakończenie transakcji ukrytych przed kontynuacją innych procesów. Jeśli wybrano wartość No, Jet będzie przetwarzał transakcje ukryte asynchronicznie No (Nie) \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbImplicit CommitSync Tabela 14.1 Ustawienia rejestru dla silnika Jet 4.0 (ciąg dalszy) Klucz Opis Wartość Domyślna Miejsce Klucza Stała dla metody SetOption LockDlay Liczba milisekund zanim Jet podejmie następną próbę blokowania 100 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbLockDelay LockRetry Ilość prób, jakie Jet podejmie w celu zablokowania strony 20 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbLockRetry MaxBufferSize Rozmiar bufora silnika Jet w kilobajtach 0 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbMaxBuffer Size MaxLocksPerFile Maksymalna liczba blokowań dla jednej transakcji. Jeśli transakcja wymaga więcej blokowań, zostanie ona podzielona na kilka innych, które będą wykonywane osobno. Ustawienie to może stwarzać problemy w przypadku Novell NetWare 3.1 9500 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbMaxLocksPer File PagesLockedToTableLock (Nowość w Accessie 2000). Nadaje wyłączny dostęp do tabel w celu dokonywania aktualizacji poprzez programową kontrolę nad liczbą blokowań strony, zanim Jet spróbuje zablokować całą tabelę. Ustawienie 50 sprawi, że Jet spróbuje zablokować tabelę za 51 razem. Jeśli to się nie uda, Jet spróbuje kolejny raz za 101 razem. Wartość zero wyłącza tę opcję 0 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 Tabela 14.1 Ustawienia rejestru dla silnika Jet 4.0 (ciąg dalszy) Klucz Opis Wartość Domyślna Miejsce Klucza Stała dla metody SetOption PageTimeout Ilość czasu, przez jaki niezablokowana przed odczytem strona jest przechowywana w buforze, zanim zostanie odświeżona. Czas mierzony jest w milisekundach 5000 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbPageTimeout RecycleLVs Określa, czy Jet będzie odzyskiwał obiekty OLE, memo i strony binarne 0 (wyłączony) \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET\4.0\ENGINES\JET4.0 dbRecycleLVs SharedAsyncDelay Liczba milisekund, jakie Jet musi odczekać przed wykonaniem ukrytej transakcji w środowisku ogólnym 50 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbSharedAsync Delay Threads Ilość wątków używanych w tle przez Jet 3 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 Brak UserCommitSync Określa, czy system czeka na zakończenie operacji zapisu przed kontynuowaniem innych procesów. Jeśli wybrano wartość No, Jet będzie przetwarzał transakcje jawne asynchronicznie Yes (Tak) \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 dbUserCommit Sync CompactByPKey Określa kolejność sortowania kluczy podstawowych. Jeśli wybrano wartość 1, Jet będzie ustawiał rekordy według wartości klucza podstawowego. W przypadku ustawienia 0, rekordy pozostaną w kolejności ich wprowadzania (kolejność naturalna) 1 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 Brak Tabela 14.1 Ustawienia rejestru dla silnika Jet 4.0 (ciąg dalszy) Klucz Opis Wartość Domyślna Miejsce Klucza Stała dla metody SetOption SystemDB Nazwa i pełna ścieżka dostępu do pliku grupy roboczej acces_path\ system.md \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 Brak PrevFormatCompactWith UNICODECompression (Nowość w Accessie 2000). Umożliwia lub blokuje kompresję pól tekstowych i memo. Domyślnie kompresja jest dozwolona. 1 \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 JetShowPlan Opcja ta jest domyślnie zainstalowana. Gdy zostanie utworzona przez programistę i ustawiona na On (uwaga na dużą literę), Jet tworzy i umieszcza w bieżącym katalogu plik tekstowy o nazwie showplan.out. Gdy kwerendy są wykonywane, informacje o tym zapisywane są w tym pliku. Pamiętaj o wyłączeniu tej opcji po zakończeniu tworzenia aplikacji. Domyślnie nie zainstalowano \HKEY_LOCAL_MACHINES \SOFTWARE\MICROSOFT\JET \4.0\ENGINES\JET4.0 Brak Bezpieczne modyfikowanie ustawień silnika Jet Istnieją trzy sposoby modyfikowania ustawień rejestru silnika Jet: ? Bezpośrednie edytowanie wartości przez Regedit.exe. ? Tworzenie profilu użytkownika w celu pominięcia ustawień domyślnych i odwoływanie się do tego profilu przy użyciu wiersza poleceń profilu. ? Umożliwienie aplikacjom tymczasowego pomijania ustawień domyślnych poprzez użycie metody SetOption obiektu bazy danych. Proponujemy korzystanie z trzeciej opcji. Nie tylko dlatego, że jest prosta w użyciu, ale również dlatego, że umożliwia modyfikowanie ustawień dla każdej aplikacji z osobna. Aby naprawdę zoptymalizować wydajność, możesz nawet zmieniać ustawienia w różnych częściach aplikacji. Technika ta nigdy nie powoduje zmiany ustawień domyślnych, tak więc tworzenie nowych projektów rozpoczyna się w tym samym miejscu. Aby tymczasowo pomijać wartości rejestru, nie musisz odwoływać się do interfejsu API. Silnik bazy danych posiada odpowiednią metodę i dwa argumenty. Składnia jest następująca: DBEngine.SetOption StałaNazwaUstawienia, Wartość Przykładowo, wydajność niektórych aktualizacji może wzrosnąć dzięki temu, że Jet będzie czekał przed wykonaniem transakcji ukrytych. Kod, który czasowo wydłuży czas oczekiwania SharedAsyncDelay do 1 sekundy (1000 milisekund), wygląda następująco: DBEngine.SetOption dbSharedAsyncDelay, 1000 Ustawienie to działa do momentu, aż aplikacja dokona jego zmiany za pomocą metody SetOption, DBEngine wyjdzie poza zakres lub aplikacja zostanie zamknięta. SetOption nie zapisuje wartości do Rejestru. Za pomocą metody SetOption nie możesz zmieniać wartości domyślnych dla SystemDB, CompactByPKey ani wątków. Jeśli Twoja aplikacja używa źródła danych ODBC, przejrzyj ustawienia rejestru w \HKEY_LOCAL_MACHINES\SOFTWARE\MICROSOFT\JET\4.0 \ENGINES\ODBC. Narzędzia służące do pomiaru wydajności Ważne jest, czy łączny wynik Twoich działań spowodował poprawę, a nie obniżenie wydajności aplikacji. Do monitorowania i oceny wydajności jednej techniki względem innej służy klika narzędzi. Pierwszym z nich jest zegar, który mierzy czas wykonywania określonych procesów. Drugim z nich jest nieudokumentowana funkcja, która liczy operacje wykonywane z użyciem dysku, bufora i blokowania. Trzecie narzędzie to opcja Accessa, dzięki której możesz przeglądać plan wykonywania kwerendy. Pierwsze dwa z tych rozwiązań możesz stosować na prawie każdej z przedstawionych w tym rozdziale technik. Plany wykonywania kwerend mają zastosowanie tylko w przypadku optymalizowania pracy kwerend. Mimo iż VBA posiada funkcję Timer(), może ona być niewystarczająca do oceny działań optymalizacyjnych. Funkcja ta mierzy w sekundach upływ czasu od momentu 0:00. Jest ona jednak mało precyzyjna i może nie być odpowiednia do Twoich celów szczególnie, gdy chcesz mierzyć operacje trwające mniej niż 1 sekundę. Wielu programistów używa funkcji GetTickCount. Mimo iż wydaje się, że funkcja ta zwraca czas w milisekundach, ponieważ jest ona związana z zegarem komputera, w rzeczywistości mierzy ona czas co 1/18 sekundy, co nie do końca odpowiada milisekundzie. Interfejs API systemu Windows posiada zegar, który mierzy czas w milisekundach. Funkcja timeGetTime() mierzy upływ czasu od momentu uruchomienia systemu Windows. Ponieważ używa innego zegara sprzętowego niż GetTickCount, zwraca czas mierzony z dokładnością do milisekundy. Używając timeGetTime(), możemy wstawić linię kodu przed i za żądanym miejscem i otrzymamy bardzo dokładny pomiar długości trwania danej czynności. Do odwołania się do interfejsu API potrzebujemy dwóch rzeczy: deklaracji funkcji i zmiennej globalnej, która posłuży do przechowywania początkowego czasu zegara. W części deklaracyjnej modułu wprowadź następujące trzy linie: Private Declare Function a2ku_apigettime Lib "winmm.dll" _ Alias "timeGetTime" () As Long Dim lngstartingtime As Long Teraz możesz utworzyć procedurę, która uruchomi zegar i funkcję, która go zatrzyma. Sub a2kuStartClock() lngstartingtime = a2ku_apigettime() End Sub Function a2kuEndClock() a2kuEndClock = a2ku_apigettime() – lngstartingtime End Function Wydruk 14.1 ilustruje wykorzystanie tych funkcji do oceny wydajności kwerendy. Wydruk 14.1. Obliczanie czasu wykonywania kwerendy Sub QueryTimer(strQueryName As String) Dim db As Database Dim qry As QueryDef Dim rs As Recordset Set db = CurrentDb() Set qry = db.QueryDefs(strQueryName) 'Uruchom zegar a2kuStartClock Set rs = qry.OpenRecordset() 'Zatrzymaj zegar i wyświetl rezultat w oknie Debug Debug.Print strQueryName & " Wykonano w: " & a2kuEndClock &_ " milisekund" rs.Close End Sub Aby otrzymać jak najdokładniejsze wyniki, umieść odwołania a2kuStartClock i a2kuEndClock jak najbliżej analizowanej procedury. Spojrzenie za kulisy Mimo iż mierzenie czasu jest ważne, nie pozwala ocenić wydajności w trakcie tworzenia aplikacji. Najprawdopodobniej tworzenie aplikacji ma miejsce na platformie dużo szybszej niż te, na których będzie używana, a testowanie odbywa się na mniejszym niż w rzeczywistości zestawie danych. Co więcej, zegar nie daje odpowiedzi na pytanie, jak aplikacja będzie działać na komputerze z mniejszą ilością pamięci lub mniejszym twardym dyskiem. Aby zajrzeć za kulisy Twojej aplikacji, możesz użyć kolejnej nieudokumentowanej funkcji: ISAMStats. Funkcja moża dać Ci kilka cennych wskazówek na temat funkcjonowania aplikacji. Mierzy ona sześć operacji mających wpływ na wydajność: odczyty z dysku, zapisy na dysku, odczyty z bufora, odczyty z wyprzedzeniem z bufora, ustanowienia blokowania oraz zdjęcia blokowania. Funkcja ta działa zarówno w Accessie 2000, jak i we wcześniejszych wersjach tego programu. Jej składnia jest bardzo prosta: DBEngine.ISAMStats (Opcja, [reset]) Oto sześć możliwości argumentu Opcja: Argument dla Opcja Opis 0 Zapis na dysku 1 Odczyt z dysku 2 Odczyt z bufora 3 Odczyt z bufora (odczyty z wyprzedzeniem) 4 Ustanowienie blokowania 5 Zdjęcie blokowania Opcjonalny argument reset umożliwia wyzerowanie indywidualnych liczników. W celu użycia tej funkcji do pomiaru wydajności musisz odjąć jeden odczyt od drugiego lub wyzerować licznik i wykonać operację. Wydruk 14.2 zawiera przykład użycia funkcji ISAMStats celem pomiaru wydajności: Wydruk 14.2. Sposób użycia funkcji ISAMStats do pomiaru wydajności Sub PrintStats() Dim i As Integer Debug.Print Debug.Print "Zapis na dysku: " & ISAMStats(0, False) Debug.Print "Odczyt z dysku: " & ISAMStats(1, False) Debug.Print "Odczyt z bufora: " & ISAMStats(2, False) Debug.Print "Odczyt z wyprzedzeniem z bufora: " & _ ISAMStats(3, False) Debug.Print "Ustanowienie blokowania: " & ISAMStats(4, False) Debug.Print "Zdjęcie blokowania: " & ISAMStats(5, False) For i = 0 To 6 ISAMStats i, True Next End Sub PrintStats pokaże, dlaczego jedna technika może być lepsza od innej. Informacja ta może Ci również pomóc w dokonaniu racjonalnego wyboru między dwiema technikami, których czas wykonywania w milisekundach jest taki sam. Dzięki tym informacjom zobaczysz, jak duży wpływ na wydajność różnych technik mają różnice w konfiguracji czy wielkości zestawu danych. Funkcje A2KU_TimeClock i PrintStats przydają się tylko w przypadku porównywania różnych technik między sobą. Co więcej, wyniki tych testów będą wiarygodne tylko wówczas, gdy będziesz je przeprowadzał wielokrotnie, w różnych warunkach, i wyciągał średnie z ich wyników. Możesz bez trudu połączyć te dwie funkcje w jedną, by za jej pomocą przeprowadzać odpowiednie testy i sporządzać z nich raporty. W dalszej części tego rozdziału wykorzystamy te dwie funkcje, aby pokazać, jak można ich używać i jak wykazać różnicę między dwiema technikami. Optymalizacja bazy danych od podstaw Relacyjne bazy danych, do których również zaliczamy Accessa opierają się na tabelach, w których zawarte są informacje. Sposób, w jaki te tabele oraz relacje między nimi są zaprojektowane, ma duży wpływ na wydajność aplikacji. Jeśli tabele nie są znormalizowane, zindeksowane, a relacje między nimi ustanowione są w niewłaściwy sposób, wykonanie każdej kwerendy i procedury będzie zabierać dużo więcej czasu. Najlepsza rzecz, jaką możesz uczynić dla poprawy wydajności bazy danych, to prawidłowo zaprojektować tabele. Projektowanie tabel w celu osiągnięcia poprawy wydajności Oprócz generalnej zasady, jaką jest normalizacja, podczas tworzenia tabel powinieneś pamiętać o poniższych punktach: ? Gdy pracujesz z połączonymi tabelami, spraw, by łącza między nimi miały charakter stały. ? Negatywny wpływ na wydajność ma użycie w tabelach prostych podarkuszy danych, gdzie podarkusz jest drugą tabelą, a łącza pola nadrzędnego i podrzędnego używają pól indeksowanych. Jednakże użycie bardziej złożonego podarkusza danych mogłoby zrównoważyć ten negatywny efekt. Zamiast w tabelach, używaj podarkuszy w kwerendach. W ten sposób możesz z nich korzystać tylko wtedy, gdy tego potrzebujesz, a nie za każdym razem, gdy otwierasz tabelę. ? Maski wprowadzania, pola odniesienia i reguły poprawności powinny również być używane tam, gdzie są potrzebne – w formularzach. Najlepiej jest, by tabele były tak proste jak tylko to możliwe. ? Nie twórz większych pól niż to konieczne. Access rezerwuje miejsce na dane według rozmiaru danego pola. Możesz zmarnować dużo miejsca (i czasu), używając typów danych lub ustawień właściwości zbyt dużych dla danych, które znajdują się w tych polach. Normalizacja danych w celu osiągnięcia poprawy wydajności O normalizacji już w tej książce mówiliśmy, teraz tylko zwrócimy uwagę na kilka jej aspektów: ? Znormalizowana baza danych pozwala zaoszczędzić przestrzeń dyskową, gdyż nie powtarza bez potrzeby danych. ? Znormalizowana baza danych używa mniejszej ilości stron danych i stron indeksów, co skraca czas wyszukiwania danych. ? W znormalizowanej bazie danych prawdopodobieństwo wystąpienia konfliktu lub pomyłki w danych jest mniejsze, gdyż powtarzają się one rzadziej. ? Kiedy można zrezygnować z normalizacji? Można to zrobić, gdy chcesz oprzeć aplikację na nieznormalizowanych tabelach, jeśli będą one tabelami tymczasowymi, których tworzenie jest czasochłonne. Jednakże dane powinny być zawsze przechowywane w znormalizowanej strukturze. Pamiętaj, że będziesz musiał stworzyć procedury, które będą aktualizować znormalizowaną strukturę o czynności wykonywane, na nieznormalizowanej strukturze – to może wpłynąć na poprawę wydajności. Łamanie reguł normalizacji powinno być jednak ostatecznością. ? Innym przypadkiem, w którym zazwyczaj możesz bezkarnie rezygnować z normalizacji, jest reguła powtarzalności danych, gdy dotyczy ona danych drugorzędnych. Często zdarza się, że w jednej tabeli przechowywanych jest mnóstwo informacji o kliencie lub produkcie, które, jeśli by przestrzegać zasad, powinny być umieszczone w osobnych tabelach (np. służbowe i domowe numery telefonów, numery faksu, numery telefonów komórkowych, numery pagerów, adresy e-mail itd.). ? Łam zasady normalizacji tylko wtedy, gdy ma to sens. Może to czasami wpłynąć korzystnie na wydajność części aplikacji. Pamiętaj jednak, że może się to odbić na stabilności i późniejszej obsłudze bazy danych oraz na integralności danych. Idealny schemat normalizacji zakładałby tworzenie tabeli o przedstawicielach z polem ID klienta, typem kontaktu, innym polem do przechowywania numerów telefonów i jeszcze innym do adresów e-mail. Jest to jednak pewna przesada i osiągnięta w ten sposób integralność i elastyczność nie zrównoważyłyby utraty wydajności. Całkiem rozsądne jest przechowywanie tych danych w tabeli o klientach i korzystanie z wyższej wydajności. Jednakże co do zasady, powinieneś normalizować wszystko co tylko możliwe. Tego właśnie oczekuje silnik Jet, który najlepiej pracuje na znormalizowanych danych. Tworzenie indeksów w celu przyspieszenia pracy kwerend ? Indeksy mogą dziesięciokrotnie przyspieszyć pobieranie danych. ? Indeksy mogą również spowolnić aktualizowanie i wprowadzanie danych, więc unikaj tworzenia zbędnych indeksów. ? Twórz takie klucze podstawowe, które są zrozumiałe dla danych i dla użytkowników. Z punktu widzenia wydajności umożliwienie Accessowi tworzenie pól klucza podstawowego przez wstawianie pola Autonumerowanie jest praktycznie bezużyteczne. Powinieneś używać czegoś, co posiada większe znaczenie, chyba że użytkownicy nie znajdują innego sposobu na identyfikowanie rekordów. Niech będzie to numer telefonu, numer PESEL, numer konta, kod sprzedawcy itp. Aby indeks naprawdę wpływał na poprawę wydajności kwerendy, musi być wykorzystywany w kwerendzie. ? Indeksuj wszystkie te pola w tabeli, których będziesz używał jako kryterium. Indeksowanie kilku pól w tabeli ułatwi optymalizowanie utworzonych później kwerend. ? Indeksuj pola po obu stronach przewidywanego sprzężenia. Ponieważ pola Numer Zamówienia jest w relacji zarówno z tabelami Szczegóły Zamówień, jak i Zamówienia, obie te tabele powinny posiadać odpowiedni indeks. Jeśli jednak masz zamiar tworzyć wiele raportów według pola Data Zamówienia, również to pole powinno być indeksowane. Wcześniejsze tworzenie relacji jako sposób na poprawę wydajności Do tworzenia relacji między tabelami używaj okna Relacje. Wykonując tę czynność w tym oknie, masz możliwość określenia właściwości tworzonej relacji. Dzięki temu również poinformujesz Jet o jej istnieniu. Będzie on wówczas w stanie wykorzystać te informacje do przygotowania bardziej efektywnego planu optymalizacji, który zostanie wykorzystany podczas tworzenia kwerend. Ma to wpływ na poprawę wydajności. Krótko mówiąc, normalizuj dane, gdy jest to konieczne twórz indeksy, bądź oszczędny przy określaniu typów danych i rozmiarów pól oraz pamiętaj o tworzeniu prostych tabel. Ich celem jest przechowywanie danych, a nie ich prezentowanie. Poprawa wydajności kwerend Mimo iż użytkownicy mogą nigdy nie zobaczyć, jak wyglądają kwerendy, to one właśnie wykonują większość pracy w aplikacji. Relacyjna baza danych byłaby bezużyteczna, gdyby nie można było tworzyć w niej kwerend. Jednak nie wszystkie kwerendy tworzone są w ten sam sposób. Nawet gdy wykonałeś wszystkie czynności niezbędne do znormalizowania danych oraz utworzyłeś wszystkie wymagane indeksy, może się okazać, że kwerendy nie będą działać tak szybko jak powinny. Może się nawet zdarzyć, że dwie kwerendy zwracające ten sam zestaw wyników będą miały różną wydajność. Aby zrozumieć, jak działa optymalizacja kwerend, musisz poznać sposób, w jaki obchodzi się z nimi Jet. Każda kwerenda przechodzi cztery etapy: 66. Definicja – przy użyciu jednego z kilku narzędzi tworzona jest instrukcja SQL. 67. Kompilacja – ciąg SQL jest dzielony na części. 68. Optymalizacja – używając działającego w oparciu o koszt algorytmu, Jet tworzy i testuje różne sposoby otrzymania żądanego zestawu wyników. 69. Wykonanie – używając optymalnego planu, Jet dostarcza użytkownikowi zestaw wyników. Kwerendę możesz definiować poprzez siatkę QBE, ciąg SQL wykonywany w kodzie, ciąg SQL we właściwości Źródło wierszy formularza, raportu lub formantu lub w każdy inny sposób, który powoduje powstanie ciągu SQL. Jet umieszcza części ciągu w hierarchicznej, wewnętrznej strukturze. Części te przypominają słowa kluczowe instrukcji SQL. Tabela podstawowa użyta przez kwerendę (From) stanowi podstawę. Następnie ustawiane są kolumny zestawu wyników (Select). Później ustawiane są kryteria i ograniczenia (Where), które musi spełnić kwerenda. Kolejnym elementem są informacje o relacjach tabeli podstawowej (Join). Ostatnia część to informacja o sposobie sortowania zestawu wyników (Order by). Struktura ta charakterystyczna jest dla fazy optymalizacji. Optymalizacja to najbardziej złożony etap. Jet wycenia i oblicza koszt każdego z możliwych rozwiązań. Dokonuje tego na dwa sposoby: uzyskując dostęp do tabel bazowych i sprawdzając istniejące między nimi sprzężenia. Zrozumienie sposobu, w jaki Jet postrzega kwerendy, może pomóc Ci w projektowaniu szybszych kwerend w przyszłości. Jet pobiera wiersze z tabel na trzy sposoby: ? Skanowanie – jest to najdroższe rozwiązanie. Jet przeszukuje każdy wiersz bez użycia indeksu. Kwerenda wymusi na aparacie Jet skanowanie tabeli jeśli: Jej ograniczenie dotyczy nieindeksowanego pola. Duża część wierszy tabeli spełnia kryteria kwerendy. ? Indeksowanie – Jet używa do przeszukiwania wierszy tabeli jej indeksu. Mimo, iż może się zdarzyć, że Jet będzie odczytywał stronę z danymi więcej niż raz, rozwiązanie to jest dużo szybsze niż skanowanie. ? Optymalizacja Rushmore – opcja ta dostępna jest tylko w sytuacji, w której ustanowione w kwerendzie ograniczenia dotyczą więcej niż jednego indeksu. Rushmore umożliwia silnikowi Jet znaczne zmniejszenie (w niektórych przypadkach nawet do zera) ilości odczytywanych stron z danymi. Dzięki użyciu optymalizacji Rushmore Jet odczytuje jedynie indeksowane strony, co jest rozwiązaniem niezwykle wydajnym. Oczywistym jest, że jeśli to tylko możliwe, powinieneś unikać skanowania i jak najlepiej wykorzystywać indeksy. Ale jak sprawdzić, czy najlepsze z rozwiązań – optymalizacja Rushmore – będzie działać na danej kwerendzie? Nie ma sposobu na włączenie lub wyłączenie technologii Rushmore, nie istnieją również żadne opisujące ją wskaźniki. Jest ona zawsze włączona, lecz tylko niektóre z rodzajów kwerend mogą z niej korzystać. Aby kwerenda wykorzystywała optymalizację Rushmore muszą być spełnione trzy warunki: ? Kwerenda musi posiadać kilka indeksów. ? Kryteria kwerendy muszą dotyczyć pól z indeksami. ? Instrukcje kryteriów muszą używać tych indeksów na jeden z trzech sposobów: ? Część wspólna – wyrażenie kryterium z operatorem „AND”. Jet mógłby w tym przypadku skorzystać z optymalizacji Rushmore, gdyż oba te pola są indeksowane. WHERE NazwaFirmy='Ernst Handle' And Miasto='Graz' ? Połączenie – wyrażenie kryterium z operatorem „OR”. Jet mógłby w tym przypadku skorzystać z optymalizacji Rushmore, gdyż oba te pola są indeksowane. WHERE NazwaFirmy='Ernst Handle' Or Miasto='Graz' ? Zliczanie – podlicza kwerendę, zwracając jedynie liczbę rekordów. Rushmore zoptymalizuje tę kwerendę nawet przy braku ograniczeń w warunku Where. SELECT Count(*) FROM Klienci; Upewnij się, że we wszystkich tabelach, które mogą z tego skorzystać, umieściłeś indeksy. Spróbuj również tak konstruować kwerendy, by można było uzyskiwać części wspólne i połączenia tych indeksów. Wykorzystanie tych dwóch wskazówek powinno załatwić sprawę operacji tabel podstawowych w planie wykonywania kwerendy. Gdy Jet wybrał już sposób dostępu do danych w pojedynczych tabelach, musi sprawdzić, jakie między tabelami występują relacje. Tę fazę optymalizacji można by nazwać określaniem strategii sprzężenia. W przewidywaniu strategii sprzężenia planu wykonywania pomoże Ci znajdująca się w tabeli 14.2 charakterystyka typów strategii. Tabela 14.2. Typy złączeń: jak działają i jak je rozpoznać Typ sprzężenia Sposób działania Cechy charakterystyczne Użycie Indeks-Połączenie Większość pracy wykonują indeksy Indeksy użyte są po obu stronach relacji. Co najmniej jeden z indeksów nie dopuszcza wartości null (klucz podstawowy). Wszystkie tabele muszą być w rodzimym formacie aparatu Jet Gdy tylko to możliwe Tabela 14.2. Typy złączeń: jak działają i jak je rozpoznać Typ sprzężenia Sposób działania Cechy charakterystyczne Użycie Indeks Pierwsza tabela jest skanowana, a następnie, przy użyciu indeksów, odnajdywane są wiersze w drugiej tabeli Indeks użyty jest w polu (polach) relacji drugiej tabeli. W indeksach tych możliwe są wartości null. Ograniczenia nie używają indeksów Jeśli w drugiej tabeli jest niewiele rekordów, jeśli jej rekordy nie są wyświetlane w zestawie wyników lub jeśli ograniczenie w kryterium pierwszej tabeli jest bardzo wąskie Połączenie Obie tabele skanowane są jednocześnie Dwie tabele sortowane według sprzężonych pól. Dane z obu tabel wyświetlane są w zestawie wyników Obie tabele są duże i sortowane według pól w relacji Odnośnik Druga tabela jest sortowana i skanowana przed sprzężeniem Brak indeksów w polach sprzężonych obu tabel Gdy druga tabela jest mała i nie ma indeksu w polu relacji tej tabeli Iteracja zagnieżdżona Iteracja wiersz po wierszu przez każdą tabelę w relacji Brak indeksów po obu stronach sprzężenia Tylko na bardzo małych tabelach i gdy nie ma innego rozwiązania Wybór typu zestawu wyników zapewniającego optymalną wydajność Jet bierze również pod uwagę żądany zestaw wyników. Przykładowo, aby przedstawić dynamiczny zestaw rekordów (dynaset), użyje on planu, który umożliwi efektywne zaprezentowanie pierwszej strony danych nawet, jeśli plan ten będzie wolniejszy przy prezentowaniu pozostałych rekordów. Do stworzenia dynasetu Jet użyje zestawu unikalnych wartości klucza, które wskażą wiersze w podległych tabelach podstawowych. Dzięki temu, wystarczy, że Jet zaprezentuje tylko wartości klucza, a dalsza część rekordów może zostać odsłonięta dopiero, gdy zażyczy sobie tego użytkownik. Natomiast w przypadku zdjęcia, Jet zbiera wszystkie rekordy i kolumny, zanim zaprezentuje wyniki. Jeśli całe zdjęcie nie mieści się w pamięci, zostanie przerzucony do pliku wymiany, co będzie miało negatywny wpływ na wydajność. Większą wydajność uzyskałbyś więc z dużego dynasetu niż dużego zdjęcia. Najpierw Jet wycenia opcje dostępu do tabel podstawowych. Każdy plan dostępu do tabeli podstawowej otrzymuje ocenę. Następnie Jet wycenia dostępne opcje sprzężenia i przyznaje im oceny. Jet będzie brał jedynie pod uwagę sprzężenie wyników relacji z tabelą podstawową. Nie bierze zaś pod uwagę sprzężenia wyników jednego sprzężenia z drugim. Umożliwia to ograniczenie czasu, jaki Jet poświęci na optymalizację kwerend. Po przeanalizowaniu każdej możliwej strategii sprzężenia i każdej możliwej strategii dostępu do tabeli podstawowej oraz po uwzględnieniu żądanego typu zestawu wyników Jet wybierze plan. W przypadku tabel nie korzystających z ODBC Jet oczyści, zmniejszy i przekaże plan do wykonania. Taka kompilacja i optymalizacja ma miejsce, gdy po raz pierwszy tworzysz, modyfikujesz lub uruchamiasz kwerendę. Kwerenda może pozostać nieskompilowana, jeśli zmodyfikujesz ją i zapiszesz, ale nie uruchomisz. Również w przypadku, gdy modyfikujesz indeksy tabeli lub schemat danych, kwerendy mogą nie być optymalizowane. Pamiętaj, by zawsze przed dostarczeniem aplikacji użytkownikom otwierać kwerendy w widoku Projekt, zapisywać je i uruchamiać. Dzięki temu będziesz miał pewność, że kwerendy są skompilowane. W celu zoptymalizowania kwerend, Jet wykonuje kompleksową ocenę kosztów. Pośród elementów tej oceny znajduje się przegląd statystyk bazy danych. Statystyki te mówią, ile w bazie danych istnieje stron danych, stron indeksowanych, wierszy w tabelach i innych elementów. Statystyki te mogą być zniekształcone, jeśli baza została w nieprzewidziany sposób zamknięta, wstrzymano transakcje lub baza wymaga zmniejszenia. Pamiętaj, by przed optymalizacją wykonać kompaktowanie bazy danych. Jak już pisaliśmy wcześniej, Jet tworzy plan wykonywania dla każdej kwerendy. Tworząc w rejestrze wpis \HKEY_LOCAL_MACHINES\SOFTWARE\MICROSOFT\JET\4.0\ENGINES\DEBUG i ustawiając jego wartość ciągu na On, Jet utworzy w bieżącym folderze plik tekstowy, zawierający plan wykonywania kwerendy. Wiele z omówionych już tematów pojawia się w planie optymalizacji kwerendy. Nie masz możliwości modyfikowania planu, chyba że poprzez zmianę schematu danych, konstrukcję kwerendy lub ograniczenia w kwerendzie. Im plan bardziej szczegółowy, tym lepiej. Wydruk 14.3 przedstawia plan wykonywania kwerendy Zamówienia Kwartalne w bazie Northwind. Wydruk 14.3. Plan wykonywania kwerendy, korzystający z optymalizacji Rushmore --- Quarterly Orders --- -Inputs to Query- Table "Customers" Using index "Primary Key" Having Indexes: Primary Key 91 Entries, 1 page, 91 Values Which has 1 column, fixed unique, primary – key, no – nulls Postal Code 91 Entries, 1 page, 87 Values Which has 1 column, fixed Company Name 91 Entries, 3 pages, 91 Values Which has 1 column, fixed City 91 Entries, 1 page, 69 Values Which has 1 column, fixed Table "Orders" -End inputs to query- 01) Restrict rows of table Orders using rushmore for expression "Orders.OrderDate Between #1/1/98# And #12/31/98#" 02) Outer Join result of "01)" to table "Customers" using index "Customers!PrimaryKey" join expression "Orders.CustomerID=Customers.CustomerID" 03) Sort Distinct result of "02)" Możesz zauważyć sekcję tabeli podstawowej, z analizą indeksów i liczbą elementów, baz danych, indeksowanych stron oraz przetwarzanych wartości. Zauważ również, że Rushmore może optymalizować tę kwerendę dzięki indeksowi w polu Data Zmówienia tabeli Zamówienia. Plan rozpoznaje sprzężenie między tabelami Zamówienia i Klienci jako sprzężenie zewnętrzne. Indeksy i technologia Rushmore sprawiają, że kwerenda ta jest bardzo dobrze zoptymalizowana. Jeśli nie jesteś pewien, jak zoptymalizowana jest dana kwerenda, przejrzyj jej plan wykonywania. Funkcja SHOWPLAN jest nieudokumentowana. W przypadku niektórych kwerend nie zwróci planu, niektóre z planów mogą być nieprawidłowe, wciąż jednak możesz ją wykorzystać. Wydruk 14.4 przedstawia słabo zoptymalizowaną kwerendę. Wydruk 14.4. Plan słabo zoptymalizowanej kwerendy, która nie korzysta z zalet optymalizacji aparatu Jet SELECT Customers.CustomerID, Customers.CompanyName FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID WHERE ((Not (Orders.ShipCountry)="USA")); ..Customers with Shipping Adress Outside USA -Inputs to Query- Table "Orders" Table "Customers" Using index "Primary Key" Having Indexes: Primary Key 91 Entries, 1 page, 91 Values Which has 1 column, fixed unique, primary – key, no – nulls Postal Code 91 Entries, 1 page, 87 Values Which has 1 column, fixed Company Name 91 Entries, 3 pages, 91 Values Which has 1 column, fixed City 91 Entries, 1 page, 69 Values Which has 1 column, fixed -End inputs to query- 01) Restrict rows of table Orders by scanning testing expression "Not Orders.ShipCountry="USA" 02) Inner Join result of "01)" to table „Customers” using index "Customers!PrimaryKey" join expression "Orders.CustomerID=Customers.CustomerID" Przyczyną słabości tej kwerendy jest sposób, w jaki obsługuje ograniczenie. Ponieważ ograniczenie to nie używa indeksu, kwerenda musi przeszukać tabelę i testować każdy z rekordów, by sprawdzić, czy spełnia on założone kryterium. Skanowanie tabel jest kosztowne. Wprowadzenie indeksu wpłynęłoby na znaczną poprawę wydajności tej kwerendy. Zwiększenie szybkości kwerend Optymalizacja kwerend w Jet jest dość rozbudowana, co nie oznacza, że nie możesz zrobić nic w tym kierunku samemu. Oto kilka wskazówek, które pomogą Ci przyspieszyć pracę kwerend: ? Twórz indeksy dla wszystkich pól, których zamierzasz użyć w kryteriach. ? Twórz indeksy po obu stronach sprzężeń w kwerendzie. ? Używaj kluczy podstawowych zamiast unikalnych indeksów. Ponieważ klucze podstawowe nie dopuszczają wartości null, kwerendy będą mogły korzystać z większej ilości typów sprzężeń. ? Nie umieszczaj w zestawie wyników zbędnych kolumn. Przetworzenie i wyświetlenie każdej kolumny zabiera dużo czasu. ? Unikaj używania złożonych wyrażeń w kwerendach. ? Unikaj używania funkcji IIF() (Immediate IF). IIF() przed podaniem wyniku, ponieważ musi sprawdzić zarówno prawdziwe jak i fałszywe konsekwencje. Wykonywanie tej operacji dla każdego rekordu znacznie obniża wydajność. ? Gdy używasz kwerend zagnieżdżonych, umieść obliczenia w ostatniej z nich. ? Używaj Count(*) zamiast Count([IDklienta]), poniważ Rushmore szybciej przetwarza Count(*) – nie musi szukać wartości null przed zliczaniem. ? Jeśli to możliwe, zamiast operatorów Greater than (więcej niż) i Less than (mniej niż) używaj operatora Between (między). ? Zazwyczaj (lecz nie zawsze) umieszczenie ograniczenia po stronie „jeden” relacji jest bardziej efektywne. Spróbuj przesunąć ograniczenia na stronę „wielu” i sprawdzić, jaki to miało wpływ na wydajność. Pamiętaj, by po każdej modyfikacji kryteriów sprawdzić zestaw wyników. ? Znormalizowane tabele mogą przechowywać dane na mniejszej ilości stron danych i stron indeksowanych. Traktuj normalizację jako regułę i odstępuj od niej tylko w sytuacjach, gdy nie ma innej alternatywy. ? Gdy to możliwe, zamiast sprzężeń lub złożonych kryteriów OR spróbuj używać podkwerend. Optymalny wybór zależy od wielu ukrytych czynników i tylko próba może pomóc Ci zdecydować, co wybrać. ? Sprzężeń zewnętrznych używaj tylko wtedy, gdy jest to konieczne, gdyż wymagają one automatycznie skanowania tabeli nadrzędnej w sprzężeniu. ? Używaj zapisanych kwerend parametrycznych zamiast instrukcji SQL w kodzie. Jet już skompilował kwerendy parametryczne i przygotował dla nich plan wykonywania (mimo iż nie pokazuje go funkcja SHOWPLAN.OUT). Użycie skompilowanych i zapisanych kwerend pozwoli uniknąć koniecznej w przypadku ciągu SQL oceny i optymalizacji silnika Jet. Access kompiluje ciągi SQL użyte jako źródło rekordów lub źródło wierszy w formularzach, raportach i formantach, więc pozostają one niezmienione. ? Zawsze dostarczaj skompilowane kwerendy. ? Jeśli to tylko możliwe, do obróbki danych zamiast DAO używaj kwerend. Kwerendy (SQL) są w tych zadaniach prawie zawsze szybsze niż DAO. ? Z uwagą wybieraj typ zestawu wyników. Dynaset będzie potrzebny, gdy będziesz chciał dodawać lub edytować dane. Zdjęcie lub Zdjęcie do przekazywania będą odpowiednie, jeśli chcesz jedynie odczytywać dane. Zdjęcia otwierają się dłużej, jednak szybciej się przewijają. ? Jeśli otwierasz zestaw rekordów po to, by tylko dodawać dane, otwórz go z opcją dbAppendOnly. To pozwoli Ci zapobiec usuwaniu wierszy. ? Testuj kwerendy przekazujące, gdy używasz architektury klient-serwer. Przyjrzyj się również nowym opcjom tej architektury w Accessie 2000. Kwerendy przekazujące nie zawsze są szybsze niż kwerendy wykonywane bezpośrednio na tabelach znajdujących się na serwerze, lecz zazwyczaj obciążają sieć w mniejszym stopniu. ? Duże kwerendy mogą być wykonywane lepiej, jeśli ustawisz właściwość UseTransaction (Użyj transakcji) na False (Nie). W przeciwnym wypadku, Access tworzy tabele tymczasowe. Czasami są one na tyle duże, że mają negatywny wpływ na wydajność kwerendy. ? Gdy przeprowadzasz kwerendę na danych z serwera, do obsługi tych danych użyj metod CacheStart, FillCache i EndCache. ? Gdy masz do czynienia z danymi z serwera, unikaj lokalnego przetwarzania. Przez przetwarzanie lokalne rozumiemy na przykład: złożone polecenie Group by (Grupuj według), w którym użyto słowa kluczowego Distinct, użycie operatora LIKE w polach tekstowych lub memo, wielokrotne funkcje podsumowujące w kwerendzie krzyżowej lub kwerendy krzyżowe z warunkiem ORDER. Unikaj także użycia złożonych połączeń zewnętrznych i wewnętrznych sprzężeń. Użycie takich konstrukcji spowoduje przesłanie dużych ilości danych z serwera na lokalny komputer i w rezultacie znaczne obniżenie wydajności. ? Kompaktuj bazę regularnie i sprawdzaj, czy statystyki używane przez aparat Jet do optymalizowania kwerend są poprawne. ? Jeśli to możliwe, w celach testowych wypełniaj swoje aplikacje co najmniej taką ilością danych, jaką będą wypełnione po zainstalowaniu na komputerach użytkowników. W ten sposób Jet zoptymalizuje kwerendy, używając statystyk odzwierciedlających rzeczywiste warunki, w jakich kwerendy te będą uruchamiane. ? Indeksuj pola, które będą sortowane. ? Jeśli operujesz na statycznych danych, rozważ utworzenie tabeli na podstawie kwerendy, zamiast ciągle uruchamiać kwerendę w bazie danych. ? Unikaj używania funkcji podsumowujących (Dlookup()) na tabelach, które nie należą do kwerendy. Kwerendy są najbardziej skomplikowanymi obiektami Accessa. Na szczęście Jet czuwa nad tym, aby działały one jak najlepiej. Dzięki informacjom zawartym w tym rozdziale będziesz mógł pomóc silnikowi Jet w przyspieszeniu pracy kwerend. Do sprawdzenia, które rozwiązania zapewniają najlepszą wydajność, używaj funkcji SHOWPLAN oraz procedur PrintStats i QueryTimer. Przyspieszenie funkcjonowania formularzy Ponieważ większość swojego czasu pracy użytkownicy spędzą, pracując z formularzami, powinieneś dołożyć starań, by wysiłek, jaki włożyłeś w optymalizację, nie został zniweczony przez wolne formularze. Przede wszystkim, formularze powinny być proste i oszczędne. Zacznijmy od początku Pierwszą rzeczą, jaką widzą użytkownicy po uruchomieniu aplikacji, jest formularz startowy. Może to być tylko ekran startowy z nazwą aplikacji oraz informacjami o niej lub panel przełączania, ułatwiający poruszanie się po aplikacji. Niezależnie od tego, który to z nich, dobrze jest usunąć z niego kod. Umieść kod formularza startowego w standardowym module i zostaw tylko te procedury, które są niezbędne do uruchomienia aplikacji. Ponieważ formularz będzie teraz ładował się szybciej, zrobi lepsze wrażenie na użytkowniku. Niektóre z operacji mogą być przeprowadzone później. Po usunięciu modułu z formularza zmień jego właściwość MaModuł na Nie. Dzięki temu uzyskasz prosty formularz, który powinien działać lepiej. Jednakże zmieniając właściwość MaModuł na Nie, usuwasz cały kod formularza i jego formantów. Pamiętaj o umieszczeniu tych funkcji i procedur w standardowym module, zanim zmienisz tę właściwość. Formularz startowy nie powinien zawierać formantów ActiveX, gdyż ładują się one dużo dłużej niż inne formanty. Jeśli jesteś zmuszony umieścić na formularzu formant ActiveX, ogranicz wówczas ilość pozostałych formantów. Wybierz opcję otwierania formularza w menu Autostart zamiast używać samowykonujących się makr. Szybsze pobieranie rysunków Użycie rysunków w interfejsie aplikacji to wykorzystanie graficznych możliwości Accessa. Jednakże nie wystarczy po prostu wstawić rysunki do aplikacji i oczekiwać, że będzie działać tak, jak ta część bazy Northwind, która zawiera zdjęcia pracowników. W tej części zajmiemy się użyciem elementów graficznych w bazie danych. Spróbuj używać formantu Obraz dla umieszczania rysunków. Jeśli chodzi o wyświetlanie grafiki, jest dużo bardziej wydajny niż związane i niezwiązane ramki obiektów. Podczas ładowania formularza Access musi zamalować lub wyrenderować każdy z umieszczonych na nim formantów. Nic dziwnego więc, że więcej czasu zajmuje mu renderowanie formantów, które na siebie nachodzą. Aby upewnić się, że prawidłowo rozmieściłeś formanty i nie nachodzą one na siebie, użyj poleceń Format, Odstępy w pionie i Odstępy w poziomie. Staraj się zachować jak najmniejsze nasycenie kolorów na formularzu (najlepsze rozwiązanie to czarno – białe). Im większe nasycenie kolorów bitmapy, tym więcej pamięci czasu wymagane jest do jej namalowania. Nie umieszczaj elementów graficznych oraz innych, dużych obiektów (np. pól memo i obiektów OLE) w podstawowych formularzach, tabelach i kwerendach. Przywołuj je za pomocą osobnych formularzy lub kwerend tylko wtedy, gdy użytkownik tego zażąda. Dzięki temu będziesz mógł zapobiec stracie czasu i zasobów na przedstawianie jakiegoś dużego i pamięciochłonnego obiektu, który w danym momencie może nie być potrzebny. Pamięć użyta do załadowania obiektów OLE nie jest zwolniona do momentu zamknięcia formularza, więc pamiętaj o zamykaniu formularzy, które nie są Ci już potrzebne. Podstawowy, szybki formularz Największy wpływ na szybkość pracy formularza ma ilość i typ umieszczonych na nim formantów. Każdy formant pochłania pamięć i zasoby, lecz niektóre więcej niż inne. Dla porównania, związana ramka obiektu pochłania około 40 razy więcej niż linia. Jeszcze gorzej może być w przypadku formantów ActiveX, w zależności od tego z czego się składają i jakie jest ich zadanie. Wybierając formanty do formularza, pamiętaj o informacjach z tabeli 14.3. Można przyjąć, że im większy zestaw funkcji daje Ci formant, tym więcej zasobów pochłania. Tabela 14.3 zawiera wszystkie formanty znajdujące się na pasku narzędzi projektu formularza. Policzyliśmy ilość właściwości każdego z nich i modyfikując tę liczbę o złożoność funkcji wykonywanych przez formant otrzymaliśmy względną wagę. Jest to jednak tylko wskazówka. W rzeczywistości, użycie zasobów przez formanty formularza określa sposób, w jaki je wykorzystujesz. Tabela 14.3. Względne wagi formantów formularza Typ formantu Względna waga Prostokąt 1 Linia 1 Podział strony 1 Formant karta (bez formantów) 4 Obraz (bez rysunku) 6 Formant karta 6 Podformularz (co najmniej) 6 Etykieta 8 Przycisk opcji 8 Przycisk polecenia 8 Pole wyboru 8 Tabela 14.3. Względne wagi formantów formularza (ciąg dalszy) Typ formantu Względna waga Grupa opcji (bez formantów) 8 Przycisk przełącznika 9 Pole tekstowe 10 Pole listy (co najmniej) 10 Pole listy rozwijalnej (co najmniej) 10 Formanty ActiveX 20 Niezwiązana ramka obiektu (bez rysunku) >=20 Związana ramka obiektu 30 Niektóre z formantów są wielokrotnie bardziej zasobochłonne niż inne, więc substytucja może okazać się dobrą techniką optymalizacyjną. Bardzo często zdarza się, że pole listy może zastąpić pole listy wyboru lub nawet podformularz. Rysunki mogą często korzystać z formantu Image zamiast ramki obiektu, a formant karta pomoże podzielić formularz na szybciej ładujące się części, renderując jedynie formanty na widocznej karcie. Jeśli użytkownicy mieli już do czynienia z hiperłączami w Internecie, możesz spróbować zastąpić nimi przyciski poleceń. Jeśli masz możliwość użycia prostszego formularza bez zmniejszania jego zestawu funkcji, zrób to. Istnieje kilka innych technik, które poprawią wydajność formantów: ? Ogranicz do minimum liczbę wyświetlanych pól w polach listy i polach listy rozwijalnej, a także indeksuj pola w nich wyświetlane. W polach listy rozwijalnej wyłączaj opcję Autorozwijanie, ustawiając ją na Nie. Nakazywanie Accessowi obserwacji i reagowania na każde naciśnięcie klawisza pogarsza wydajność. Używaj tej opcji tylko wtedy, gdy nie da się tego uniknąć. Jeśli musisz użyć opcji Autorozwijanie, upewnij się, że kolumna, do której użytkownik wprowadza dane, jest polem tekstowym. Access może użyć tej funkcji jedynie na tekście. Jeśli wprowadzone dane nie są tekstem, Access będzie musiał je konwertować, co zabierze więcej czasu. ? Jeśli ukrywasz pole związane formantu lista rozwijana, unikaj używania w nim lub w wyświetlanych polach wyrażeń. Pole listy rozwijalnej nie wyświetli wyników tak szybko, jakby to miało miejsce, gdyby były one obliczone wcześniej i umieszczone w tabeli. ? Unikaj używania w listach i listach rozwijalnych kwerend z ograniczeniami. Próbuj opierać je na prostych tabelach. Możesz poprawić wydajność, tworząc tabelę na podstawie kwerendy i aktualizując ją co jakiś czas. ? Podczas odświeżania formularzy lub wszystkich formantów zawierających dane, które mogły ulec zmianie, używaj metody Requery, która jest dużo szybsza niż Akcja PonówKwerendę makra. Pamiętaj o użyciu tej metody po każdej aktualizacji lub usuwaniu danych, szczególnie w aplikacjach, których używa wielu użytkowników. ? Zamiast tworzyć jedną, dużą listę rozwijalną, zastanów się, czy nie ma możliwości umieszczenia w formularzu kilku pól, które będą ograniczały swoją zawartość. Przykładowo, jedna lista rozwijana mogłaby służyć do wyboru województw. Wybór ten ograniczałby zawartość drugiej listy do miast na obszarze wybranego województwa. Byłoby to szybsze i bardziej wydajne rozwiązanie niż jedna lista, zawierająca nazwy wszystkich województw i miast. ? Tak samo, jak musisz być oszczędny w wyborze ilości i typów formantów na formularzu, powinieneś również przemyśleć ilość pól przedstawianych w podległym formularzowi zestawie rekordów. Mimo iż formularze zawsze ładują dane z tabeli szybciej niż z kwerendy, istnieje jedno zastrzeżenie. Gdy otwierasz formularz oparty na tabeli, wszystkie jej pola są ładowane, nawet, jeśli formularz ich nie wyświetla. Czasami lepiej jest oprzeć formularz na kwerendzie, co pozwoli na usunięcie zbędnych pól z zestawu rekordów. ? Podległy formularzowi zestaw rekordów sortuje jedynie w ostateczności. Wymuszenie zmiany kolejności rekordów w tym samy czasie, gdy formularz przygotowuje się do ich prezentacji, może zauważalnie wydłużyć czas otwierania formularza. ? Kiedy piszesz kod formularza (CBF), używaj słowa kluczowego Me. Stała ta zawsze odnosi się do aktywnego formularz, i działa szybciej niż inne odniesienia. ? W przypadku konstrukcji formularz główny – podformularz, indeksuj nadrzędne i Podrzędne pola łączące. To znacznie poprawi szybkość odniesień, które te formularze wykonują bardzo często. ? Jeśli użytkownicy nie będą edytować rekordów podformularza, ustaw jego właściwości w odpowiedni sposób. Edycja dozwolona, Dodawanie dozwolone i Usuwanie dozwolone mają wpływ na wydajność, gdyż zwiększają zestaw funkcji formularza. Możesz przyspieszyć jego działanie, pozbywając się zbędnych funkcji. W ten sam sposób możesz przyspieszyć działanie formularza, wybierając odpowiedni zestaw funkcji. Jeśli otwierasz formularz w celu wprowadzania danych, ustaw właściwość Wprowadzanie danych na Tak, aby nie pobierał on niepotrzebnie rekordów. ? Co się tyczy ustawiania właściwości formantów i formularza w trakcie jego działania umożliwiaj to jedynie wtedy, gdy jest to niezbędne i nie powoduje zmniejszenia wydajności. ? Czy dynamiczny zestaw rekordów jest konieczny? Może wystarczyłoby zdjęcie? ? Gdy jest to tylko możliwe, ukrywaj formanty przy użyciu podziału strony i formantu karta. Możesz również przyspieszyć działanie aplikacji, ukrywając formularze. Dobrze jest w miarę możliwości załadować kilka najczęściej używanych formularzy tak, by były niewidoczne. Możesz to uczynić podczas uruchamiania aplikacji lub przy ładowaniu pierwszego formularza. Aby załadować formularz tak, by był niewidoczny, otwórz go z argumentem WindowMode ustawionym na Hidden: DoCmd.OpenForm "NazwaFormularza" , , , , acHidden ? Gdy użytkownik będzie chciał wyświetlić formularz, możesz go wyświetlić przy użyciu następującego polecenia: Forms("NazwaFormularza").setfocus ? Jeśli użytkownik będzie znów potrzebował tego formularza, ukryj go zamiast zamykać. Metoda Hide spowoduje ukrycie go, lecz pozostanie on załadowany do pamięci. Formobject.hide ? Możesz znacznie poprawić wydajność interfejsu, unikając ładowania kwerend i formularzy oraz renderowania formantów. Ceną tego jest zajmowanie pamięci przez ukryte formularze, co może mieć wpływ na inne części aplikacji. Mimo iż nie możesz użyć tej techniki dla wszystkich formularzy w aplikacji, powinieneś ją zastosować w przypadku tych najczęściej używanych. Gdy masz do czynienia z dużymi zestawami rekordów, spróbuj nie przedstawiać ich użytkownikowi jednocześnie. I tak, większość użytkowników nie wiedziałaby co zrobić z dziesiątkami tysięcy rekordów naraz. Jeśli jednak z aplikacji korzysta wielu użytkowników, a formularz otwiera zestaw rekordów oparty na dużej tabeli lub kwerendzie, wydajność aplikacji spadnie na skutek wąskich gardeł w sieci, ograniczeń bufora, blokowania rekordów i stron oraz przeładowania użytkowników. Lepiej jest znaleźć sposób na podzielenie danych na logiczne podzestawy przy użyciu ograniczeń. Jeszcze lepiej jest przedstawiać użytkownikowi rekordy pojedynczo, pobierając je na podstawie klucza podstawowego lub indeksowanego pola. W przypadku mniejszych aplikacji, może to mieć negatywny wpływ na wydajność, jednakże w przypadku systemów z wieloma użytkownikami, jest to jedyny sposób. Aby tego dokonać, zmień instrukcje SQL w kodzie, programowo zmień właściwość Źródło rekordów i ponów kwerendę formularza. Szybsze drukowanie raportów Jaki jest pożytek z dobrej bazy danych, jeśli drukowanie raportu zajmuje cały dzień? Największą, mającą wpływ na wydajność różnicą między formularzami i raportami różnicą jest sposób, w jaki zarządzają swoimi sekcjami. W formularzu istnieje nagłówek formularza, sekcja szczegółowa i stopka formularza. W raporcie istnieje nagłówek i stopka raportu, nagłówek i stopka strony, nagłówki i stopki sekcji oraz sekcja szczegółowa. Gdy otwierasz formularz, kwerenda, na której jest oparty, przeprowadzana jest tylko raz. Gdy otwierasz raport, musi on utworzyć kwerendę (opartą na tej ze źródła danych) dla każdej sekcji raportu. W przypadku złożonej kwerendy raport musi ją lub jej części uruchamiać kilkakrotnie. Oto kilka wskazówek, które mogą wpłynąć na przyspieszenie tworzenia raportów: ? Staraj się, by kwerenda, na której oparty jest formularz, była tak prosta jak tylko to możliwe. ? Obliczenia umieszczaj w raporcie. Gdy obliczenia umieszczone są w kwerendzie, muszą być wykonywane dla każdego wiersza. Jeśli jednak umieścisz je w raporcie, użytkownik zobaczy wyniki w momencie, gdy Access wykona obliczenia dla jednej strony raportu. ? Spróbuj oprzeć kwerendę na jak najmniejszej ilości tabel. Ponieważ raport będzie uruchamiał kwerendę więcej niż raz, możesz utworzyć tabelę z zestawem rezultatów. Raport będzie szybciej przeszukiwał tabelę niż ponownie wykonywał kwerendę. Rozwiązanie to może być szczególnie efektywne, gdy masz do czynienia z kwerendą zawierającą podkwerendę. ? Unikaj podkwerend w źródle raportu. Raport potrzebuje dużo pamięci, a kwerenda z podkwerendą może pochłaniać więcej pamięci niż to konieczne. ? Czy naprawdę potrzebujesz podraportów? Podraporty nie tylko utrudniają formatowanie danych w taki sposób, w jaki byś sobie tego życzył, ale również pochłaniają pamięć i pogarszają wydajność raportu. Zdarzają się jednak sytuacje, w których warto skorzystać z podraportów. Gdy używasz wielu funkcji, użycie podraportu może okazać się szybszym rozwiązaniem niż kilka odwołań do tych funkcji. ? Unikaj wyrażeń sortujących i grupujących. Aby prawidłowo wyświetlić sortowanie i grupowanie, raport będzie musiał przeliczyć każde wyrażenie kilkakrotnie. Wykonaj obliczenia tych wartości przed przekazaniem ich do raportu. ? Indeksuj wszystkie pola używane do sortowania i grupowania. Ponieważ indeksy same sortują rekordy, łatwiej jest raportowi porządkować i grupować dane wprost z indeksowanych pól. ? Źródło rekordów nie powinno zawierać funkcji podsumowujących (DLookup). Takie rozwiązanie również wymusi na raporcie wielokrotne przeglądanie danych, co spowolni wyświetlanie raportu. ? Nie ma sensu wyświetlanie raportu wypełnionego komunikatami #Error#. Jeśli raport nie zawiera danych, poinformuj o tym użytkownika za pomocą komunikatu i zamknij raport. Możesz określić, czy raport zawiera dane za pomocą właściwości Brak danych i Ma dane. Wiele z technik umożliwiających poprawę wydajności formularzy ma również zastosowanie do raportów. Ta sekcja była omówieniem technik charakterystycznych jedynie dla tych drugich. Pisanie szybkiego kodu Co się tyczy kodu, istnieje kilka rzeczy, które mogą poprawić szybkość wykonywanych funkcji i procedur. Mimo iż różnice między jedną techniką a drugą mogą być mierzone w znaczących ułamkach sekundy, wybór najszybszej opcji może ograniczyć przyszłą rozbudowę aplikacji. Należy być przygotowanym na to, że po pewnym czasie użytkownicy poproszą o modyfikacje i lepiej jest wówczas mieć możliwość umieszczenia w niej dodatkowych elementów (np. złożonych procedur sprawdzania poprawności) bez pogorszenia wydajności aplikacji. Jeśli poświęciłeś trochę czasu na przejrzenie i wdrożenie niektórych z dotychczas omówionych technik, pisany przez Ciebie kod będzie łatwiejszy do zoptymalizowania. Największą przeszkodą w tym przypadku będzie słaby projekt bazy danych. Jeśli baza jest źle zaprojektowana, każda funkcja i procedura będzie wykonywana dłużej niż powinna. Istnieje kilka prostych zasad oraz kilka alternatywnych technik, które sprawią, że funkcje i procedury Twojej aplikacji będą wykonywane tak szybko jak to tylko możliwe. Część z nich, o ile nie wszystkie, ma raczej nieznaczny wpływ, gdy występują osobno, jednakże gdy są wykorzystane razem i powtarzane, efekt będzie zauważalny. Użycie pamięci przez kod Access używając metody „call-tree loading” przenosi do pamięci wszystkie moduły oraz wszystkie zawarte w nich procedury i funkcje. Oznacza to, że jeśli funkcja A pierwszego modułu odwołuje się do funkcji B tego samego modułu, która z kolei odwołuje się do funkcji C drugiego modułu, to Access załaduje do pamięci całą zawartość obu modułów. Stąd też dobrze jest łączyć moduły w grupy w przemyślany sposób. Jeśli funkcje i moduły często się do siebie odwołują, umieść je w tym samym module w celu zmniejszenia ilości załadowań modułu. Usuń również wszystkie zbędne funkcje i procedury. VBA ładuje moduł do pamięci również w sytuacji, w której odnosisz się do zmiennych publicznych tego modułu. Zadbaj o to, by zmienne publiczne również były pogrupowane w modułach w przemyślany sposób. Praca z modułami Przed uruchomieniem modułów VBA musi je skompilować. Oznacza to, że VBA będzie kompilować moduł za każdym razem, gdy będziesz chciał go uruchomić. Może mieć to znaczący wpływ na wydajność aplikacji. Podczas kompilowania modułu VBA nadaje mu znacznie mniejszą, łatwiej wykonywalną formę. Mimo iż początkowy kod jest zawsze przechowywany w pliku MDB, Access ładuje i uruchamia skompilowany kod VBA. Ponadto kod VBA nie zawiera pustych miejsc, komentarzy, nagłówków i zajmuje dużo mniej miejsca niż napisany przez Ciebie kod źródłowy. Jeśli chcesz uruchomić nieskompilowaną procedurę, VBA musi załadować do pamięci cały kod źródłowy (łącznie z pustymi miejscami, komentarzem i nieużywanym kodem) i skompilować go przed wykonaniem. Dotyczy to również zawierających kod formularzy i raportów. Kompilowanie kodu Aby skompilować kod, z menu Debug wybierz polecenie Compile nazwaprojektu. Pamiętaj o skompilowaniu aplikacji przed dostarczeniem jej do klientów. Dekompilacja Moduł jest dekompilowany podczas edytowania go. Raport czy formularz dekompilowany jest w momencie dokonywania w nim jakichkolwiek zmian, nawet bez ingerowania w kod. Tworzenie nowego formularza lub raportu również pociąga za sobą dekompilację kodu. Podczas tworzenia aplikacji możesz używać opcji Compile on Demand (aby ją włączyć, z menu Tools wybierz Options. Opcja Compile on Demand znajduje się na zakładce General). Dzięki temu VBA będzie kompilować moduły aplikacji podczas pracy. Nową opcją w Accessie 2000 jest Background Compile. Kompilując aplikację w tle, VBA pozwala Ci zaoszczędzić trochę czasu. Jeśli kiedyś zdarzy Ci się to sprawdzić, skompilowana aplikacja zajmuje więcej miejsca na dysku niż jej zdekompilowana wersja. Dzieje się tak, gdyż w skompilowanej aplikacji przechowywany jest zarówno źródłowy jak i skompilowany kod. Nie wpływa to jednak na obniżenie wydajności. Jako, że do pamięci ładowany jest tylko skompilowany kod, który działa szybciej niż źródłowy, w rzeczywistości następuje znaczna poprawa wydajności. Ponieważ Access przez cały czas ładuje moduły do pamięci, powinieneś sprawdzić, czy nie zawierają one żadnych zbędnych elementów (np. nie używanych funkcji czy procedur). Usuń z aplikacji kod, z którego zrezygnowałeś w trakcie procesu tworzenia. Kompilator musi zajmować się również tym kodem, co spowalnia cały proces. Czasami podczas pisania aplikacji powinieneś zamknąć projekt, co spowoduje wyczyszczenie pamięci. Nawet po skompilowaniu aplikacji wciąż będziesz jednak chciał, by jak najmniejsza część kodu ładowana była do pamięci. Tworzenie pliku MDE Najpewniejszym sposobem na to, by aplikacja była stale skompilowana, jest przekazanie jej użytkownikom w postaci pliku MDE. Plik taki nie zawiera kodu źródłowego i nigdy nie jest kompilowany. Oprócz kwestii związanych z grupowaniem modułów, zarządzaniem pamięcią i kompilacją, istnieje kilka wskazówek, których wykorzystanie przy pisaniu kodu pomoże Ci tworzyć szybsze aplikacje. Użycie Option Explicit Zawsze używaj Option Explicit, gdyż zmusi cię to do określania typów danych. Jeśli nie określisz typu danych zmiennej, VBA użyje największego i najbardziej obszernego typu danych. Jak zwykle, największy i najbardziej obszerny oznacza jednocześnie najwolniejszy. Określanie typu danych zmiennej jest również przydatne ze względu na przejrzystość i integralność danych. Precyzyjne wybieranie rozmiaru zmiennych Podczas określania zmiennej wybieraj zawsze możliwie jak najmniejszy rozmiar. Nie używaj double tam, gdzie wystarczy integer. Gdy tylko jest to możliwe, używaj ciągów o stałej zamiast o zmiennej długości. Oszczędzanie przestrzeni stosu przy użyciu zmiennych typu string Zmienne typu string należą do najczęściej używanych. Można je podzielić na trzy podtypy: ? Lokalne o stałej długości (nie więcej niż 64 znaki) – zmienne te używają dwóch bajtów na znak i nie korzystają z obszaru dynamicznego pamięci. ? Lokalne o stałej długości (więcej niż 65 znaków) – zmienne te również używają dwóch bajtów na znak, lecz w obszarze dynamicznym pamięci. Wymagają również czterech bajtów w stosie, aby wskazywać zmienną w obszarze dynamicznym pamięci. ? Długość zmienna (długość nie ma znaczenia) – wielkość użytej pamięci dynamicznej zależy od długości zmiennej. Cztery bajty pamięci stosu użyte są w celu wskazania zmiennej w obszarze dynamicznym. W przypadku ciągów znaków celem powinno być zmniejszenie ilości wykorzystywanej przez nie pamięci stosu. Spróbuj zmienić ciągi o zmiennej długości na ciągi o stałej długości. Poniższy przykład przedstawia ciąg o zmiennej długości, zadeklarowany jako ciąg o stałej długości w celu zmniejszenia używanej pamięci stosu. Dim strString as string Static strString as string * 30 Do określenia rozmiaru pól tekstowych o stałym rozmiarze używaj rozmiaru pola w tabeli. Dokładne określanie typu obiektów Gdy deklarujesz typ obiektu, bądź dokładny. Jeśli kod ma przechodzić przez pola tekstowe formularza, zadeklaruj zmienną obiektu jako pole tekstowe, nie tylko jako formant. W ten sposób nie wystąpi konieczność używania VBA do sprawdzenia, o jaki rodzaj formantu chodzi. Aby zaoszczędzić czas, zamiast Sub CycleControls(cntl as control) użyj Sub CycleControls(cntl as TextBox) Umieszczenie kodu we wnętrzu procedury zamiast odwoływania się do innych funkcji W momencie gdy funkcja lub procedura odwołuje się do innej funkcji lub procedury, występuje klasyczny konflikt między łatwością w obsłudze a szybkością. Technika ta bardzo ułatwia obsługę, lecz jest mniej wydajna niż umieszczenie kodu w jednej procedurze. Mogą zdarzyć się sytuacje, w których będziesz zmuszony wybierać między szybkością a łatwością obsługi, lecz nie rób tego tylko dla zyskania kilku milisekund. Zmiana True i False Podczas zmiany znacznika z True na False, nie zachodzi konieczność sprawdzania znacznika wartości w konstrukcji If...Then...Else. Możesz zaoszczędzić czas i linie kodu, odwracając tę wartość przy użyciu operatora NOT. Ustawiając zmienną logiczną na to, czym ona nie jest, odwracasz ja. Zamiast If bFlag = False then bFlag=True Else bFlag=False EndIf użyj bFlag=Not bFlag Wykonanie jednej linii kodu zajmuje dużo mniej czasu niż kilku, zawierających dodatkowo ocenę. Użycie Len() zamiast pustego ciągu Aby przetestować zmienną typu string w celu sprawdzenia, czy zawiera jakiekolwiek znaki, zamiast porównywania jej do pustego ciągu (""), użyj funkcji Len(). Funkcja ta dokona oceny szybciej niż porównanie z ciągiem o zerowej długości. Sub CheckString(strString as string) If Len(strString) then MsgBox „Oto ciąg: ” & strString End If End Sub Użycie True i False zamiast zera Ponieważ True i False są binarne, łatwiejsze jest ich wyliczanie niż liczby zero. Użyj True i False w następujący sposób: Function ShowNumber(dblNumber as Double) as string If dblNumber then ShowNumber = "Numer to " & dblNumber EndIf End Function Szybkie odwołania do obiektów W przypadku powtarzających się odwołań do rekordów używaj zmiennych. Dużo szybciej jest odwoływać się do istniejącej zmiennej formularza, formantu, raportu czy kwerendy niż ponownie odwoływać się do obiektów. Zamiast ponownie odwoływać się do formularza Forms![frmMyForm].Height=500 Forms![frmMyForm].Width=500 spróbuj zadeklarować zmienną i odwołać się do niej w ten sposób: Dim frm as Form Set frm=Forms![frmMyForm] frm.Height=500 frm.Width=500 W przypadku większej ilości właściwości obiektu, możesz zmniejszyć ilość odwołań przy użyciu konstrukcji With...End With. Przydaje się to szczególnie wtedy, gdy ścieżka odwołania jest długa. With Forms![frmMainForm]![txtCustomerName] .left=200 .top=300 .height=200 .width=100 End With Słowo kluczowe ME oznacza aktywny formularz, więc nie musisz deklarować zmiennej ani odnosić się do obiektu, by go użyć. Ponieważ jest to możliwe tylko w CBF, nie będziesz mógł umieszczać go w standardowych modułach ogólnych. With ME .Height=500 .Width=500 End With Użycie szybkich tablic Używaj tablic. Są one przechowywane w pamięci i ładowane są bardzo szybko. Ich powiększenie zajmuje bardzo mało czasu. Tablice zajmują tyle miejsca, ile w danym momencie potrzebują. Jeśli nie wiesz, ile elementów będziesz musiał umieścić w tablicy, zamiast tworzyć dużą tablicę z pustymi miejscami, utwórz tablicę dynamiczną. Jeśli chcesz opróżnić tablicę nie niszcząc jej struktury, możesz użyć słowa kluczowego Erase. Dzięki temu będziesz mógł wyczyścić tablicę określonego rozmiaru, bez konieczności ponownego jej budowania. Erase myArray Jeśli chcesz powiększyć tablicę bez niszczenia danych w niej zawartych, użyj funkcji ReDim z parametrem Preserve. ReDim Preserve myArray(Ubound(myArray+1)) Tablice często mogą zarządzać danymi z zestawu rekordów. Zamiast otwierać zestaw rekordów z całą jego zawartością, użyj metody GetRows() i zamknij zestaw rekordów. Dzięki temu pamięć zostanie zwolniona i nie będzie problemów związanych z obsługą wielu użytkowników. GetRows() posiada jeden argument: liczbę wierszy ładowanych do tablicy. Dim db as Database Dim rowArray as Variant Dim rs as Recordset Set db=CurrentDB() Set rs=db.openrecordset("Zamówienia kwartalne") RowArray=rs.GetRows(rs.RecordCount) rs.close ... Po załadowaniu danych do tablicy możesz obrabiać je w dowolny sposób lub umieścić je w niezwiązanym formularzu. Używaj stałych, gdy jest to tylko możliwe Za każdym razem, gdy VBA ma pobrać bieżącą wartość zmiennej, musi się do niej odwoływać. Inaczej jest w przypadku stałych. Stałe poprawiają również czytelność kodu. Zamiast wpisywać wszędzie 12 jako 12 miesięcy, utwórz stałą (na przykład o nazwie WszystkieMiesiące) i ustaw ją na 12. VBA będzie odczytywać stałą dużo szybciej, a inni programiści będą wiedzieli, co miałeś na myśli ustawiając stałą. Wadą takiego rozwiązania jest to, że stałe mogą być ustawiane tylko raz i nie mogą być później zmieniane. Można ich używać do przedstawiania wartości wewnętrznych aplikacji lub wartości zewnętrznych, które nigdy nie ulegają zmianie. Właściwe użycie zakładek (Bookmarks) Zakładki są bardzo szybkim sposobem poruszania się po rekordach w interfejsie. Pamiętaj, że istnieją dwa rodzaje zakładek: zakładki dla formularzy i zakładki dla zestawów rekordów. Zakładka formularza jest to tablica zmiennych wariantowych, dynamicznie przyznawanych do każdego rekordu w podległym zestawie. Zakładka DAO jest to bajtowa tablica, która definiuje każdy z rekordów w zestawie. Ułatwiające poruszanie się po rekordach zakładki są niszczone i tworzone ponownie wraz z zestawami rekordów. Nie polegaj na nich, chyba że możesz je kontrolować lub gdy nie będzie to miało negatywnych konsekwencji. Nie przedstawiają one rekordów i nie mają nic wspólnego z kluczem podstawowym. Reprezentują one jedynie tymczasową pozycję rekordu w serii wierszy. Jakakolwiek obróbka danych powinna być dokonywana w oparciu o techniki odnoszące się do projektu bazy danych, a nie jedynie pozycji w zestawie rekordów. Używając kwerendy po każdej operacji aktualizacji i usuwania danych, będziesz każdorazowo niszczył zakładki i tworzył je na nowo. Jeśli Twój interfejs używa w takich sytuacjach zakładek, będziesz musiał dokładnie kontrolować aktualizację i usuwanie rekordów. Poniższy kod ilustruje użycie zakładki w formularzu w celu przejścia do poprzedniego rekordu po dokonaniu aktualizacji. Private Sub Findit_AfterUpdate() Dim rsclone As Recordset Dim recordID As Variant Dim IDValue As Long Set rsclone = Me.RecordsetClone IDValue = Me![Findit] recordID = "ID = " & Value rsclone.FindFirst recordID bm = rsclone.Bookmark Me.Bookmark = bm End Sub Użycie zakładki w celu przejścia do poprzedniego rekordu jest o 1300% szybsze niż wykonanie instrukcji FindFirst w tej samej sytuacji. Zamykaj i niszcz Szybki kod to czysty kod. Pamiętaj o zamykaniu zestawów rekordów po zakończeniu pracy z nimi i o ustawianiu obiektów na Nothing, gdy nie są Ci już więcej potrzebne. Pozostawienie ich ogranicza ilość pamięci dla innych części aplikacji. rs.Close Set db=Nothing Używaj SQL zamiast DAO Przechodź przez zestawy rekordów tylko wtedy, gdy nie ma innego rozwiązania. Bazy danych Jet są optymalizowane pod kątem wykorzystania SQL do obróbki danych i ich struktury. Używaj kwerend zamiast DAO w każdej możliwej sytuacji. Niewiele jest sytuacji, w których obiekty DAO są szybsze niż dobrze zaprojektowana kwerenda. W przeciwieństwie do obiektów DAO kwerendy posiadają plany wykonywania i mogą korzystać z indeksów. Jeśli musisz odwoływać się do danych za pomocą modelu obiektowego, zamiast DAO użyj ADO. Obiekty ADO to nowy standard obróbki i definicji danych poprzez model obiektowy. Technologię DAO można uznać za schyłkową i nie są do niej wydawane żadne rozszerzenia i poprawki. W książce tej omówiliśmy funkcjonowanie obiektów ADO w kilku miejscach, zwłaszcza w rozdziale 6. „Wprowadzenie do obiektów danych ActiveX” i 7., „Zaawansowane ADO”. Użycie indeksowania kolekcji Gdy masz do czynienia z kolekcjami, jeśli to tylko możliwe używaj ich numerów indeksów. Numery te są wewnętrznymi identyfikatorami kolekcji. Ich użycie jest dużo szybsze niż innych właściwości (np. nazw). Poniższy przykład ilustruje dwa sposoby tworzenia odniesień do aktualnej bazy danych. Użycie Currentdb() powoduje automatyczne odświeżenie kolekcji bazy, co zabiera trochę czasu. Pierwszy sposób (dbEngine(0)(0)) nie odświeża zbioru. Set db=DBEngine(0)(0) jest szybszym rozwiązaniem niż Set db=Currentdb() Set cntl=Forms!frmMyForm(0) i szybszym niż Set cntl =Forms![frmMyForm]![myControl] Użycie numeru indeksu elementu zbioru przydaje się w szczególności w przypadku pętli. Tworzenie szybszych pętli Tworząc pętlę w kolekcji, zamiast For...Next używaj For...Each. Podczas tworzenia pętli w formantach formularza For Each cntl on frm ... Next będzie działać szybciej niż zwykła pętla For...Next. Podczas tworzenia pętli w obiektach Collection będziesz chciał uniknąć zbędnego odświeżania kolekcji. Nawet w przypadku małych baz danych odświeżanie kolekcji może spowodować znaczny spadek wydajności. W przypadku użycia pętli For...Next możesz zaoszczędzić czas, nie umieszczając zmiennej w linii Next. For i = 1 to 100 ' zrób co chcesz Next Płynące z takiego rozwiązania korzyści są szczególnie widoczne w przypadku pętli zagnieżdżonych. Staraj się również nie obliczać granicy w linii For. Górna granica powinna być już znana przed rozpoczęciem pętli. Reccount=rs.recordcount/2 For i=1 to reccount ... Next Jeśli nie określisz wartości górnej granicy wcześniej, pętla będzie ją obliczać za każdym przejściem. Jest to strata czasu. Usuń z kodu IIF() Nie używaj w kodzie funkcji IIF(). Zanim poda ona swoje wyniki, musi dokonać oceny wszystkich wyrażeń w niej zawartych. Szybszym rozwiązaniem jest standardowa struktura If...Then...Else. Porządkowanie Select Case Używając konstrukcji Select Case, pamiętaj o uporządkowaniu jej w taki sposób, by najczęściej występujące przypadki znajdowały się u góry. Ponieważ przejście przez Selections związane jest z testowaniem przypadków w kolejności ich ułożenia, umieszczenie najczęściej występujących u góry umożliwi jak najszybsze opuszczenie struktury. Używaj Execute zamiast RunSQL Unikaj pisania kodu w oparciu o polecenie DoCmd. DoCmd znajduje się na najwyższym poziomie kodu VBA. Gdy tylko istnieje inne rozwiązanie – wybierz je. DoCmd RunSQL „...” będzie wolniejszym rozwiązaniem od Querydef.Execute Używaj A2KU_Timer Podczas mierzenia czasu wykonywania operacji w aplikacji używaj znajdującego się na płycie CD zegara A2KU_Timer. Jest prawie 1000% szybszy niż wszystkie inne. Testuj wydajność transakcji Transakcje nie zawsze umożliwiają zaoszczędzenie czasu. Kiedyś mogłeś być pewien, że użycie transakcji spowoduje przyspieszenie pracy kwerend. Teraz już tak nie jest. Mimo iż transakcje mogą użyć swoich zdolności buforowania, w celu poprawy wydajności kwerend, mogą jednocześnie spowolnić ich pracę, ze względu na konieczność tworzenia na dysku tymczasowych plików, w oczekiwaniu na ponowny przebieg. Kontroluj odświeżanie Wyłącz Application.Echo lub kontroluj zawartość ekranu. Odświeżanie ekranu zabiera dużo czasu i może spowolnić pracę aplikacji. Używaj wczesnego wiązania i zwracaj uwagę na odniesienia ActiveX Korzystaj z wczesnego wiązania. Używając formantów ActiveX, upewnij się, że istnieje odniesienie do odpowiedniego pliku OCX dla tego formantu. Możesz to sprawdzić, wybierając z menu Tools pozycję References. Wczesne wiązanie może znacznie poprawić wydajność aplikacji. Przejście do architektury klient-serwer Staraj się, by projekt aplikacji uwzględniał możliwość przejścia do SQL Server lub Oracle. Jeśli tak się stanie, będziesz mógł skorzystać z kwerend przekazujących i procedur przechowywanych na serwerze. Może to mieć duży wpływ na wydajność aplikacji. Chleba i igrzysk Jeśli nie jesteś w stanie sprawić, by dana operacja była wykonywana szybko, spraw, by przynajmniej na taką wyglądała. Jeśli jakiś proces trwa na tyle długo, by wywołać znudzenie użytkownika, wyświetl ekran informujący go o tym, że coś się dzieje. Użytkownicy często myślą, że aplikacja działa szybko, ponieważ otrzymują o tym informacje. Część V Access i architektura klientserwer W tej części: ? Wprowadzenie do projektów programu Microsoft Access oraz narzędzi wizualnych. ? Tworzenie interfejsu użytkownika dla Microsoft SQL Server. ? Interfejs Accessa 2000 do Oracle. Rozdział 15. Wprowadzenie do projektów programu Microsoft Access oraz narzędzi wizualnych W tym rozdziale: ? Wprowadzenie do Projektów programu Microsoft Access (ADP). ? Użycie ADP. ? Praca z ADP i istniejącymi bazami danych serwera SQL. ? Tworzenie projektów opartych o nową bazę danych. Microsoft zintegrował Access 2000 z serwerem SQL, używając jako spoiwa OLE DB. Aby skorzystać z zalet tej integracji, użyj ADP, nowego typu aplikacji w Accessie. Autorzy zalecają używanie ADP do współpracy z SQL Server 7.0. Jeżeli chcesz użyć innego serwera niż SQL Server 7.0, zajrzyj do rozdziału 16., „Tworzenie interfejsu użytkownika dla Microsoft SQL Server” i rozdziału 17. „Access jako interfejs użytkownika dla Oracle”. W tym rozdziale przedstawiony jest sposób użycia ADP we współpracy z SQL Server 7.0. Wprowadzenie do projektów programu Microsoft Access Jako użytkownik Accessa wiesz, że używa on silnika bazy danych Microsoft Jet do zapisywania danych oraz wykonywania zapytań. Wiele aplikacji Accessa używa serwera bazy danych i połączenia ODBC do zapisywania danych. Aplikacje takie mogą korzystać z tabel połączonych, zapytań SQL i ODBCDirect. W takich aplikacjach używasz silnika Jet i ODBC, aby komunikować się z połączonymi tabelami, a aplikacja jest zwykłym plikiem MDB. Przedstawiciele Microsoftu zrozumieli, że potrzebujesz lepszej integracji z serwerami baz danych. W Accessie 2000 jest dostępny nowy typ projektu bazy danych nazwany Projektem programu Microsoft Access (ADP), używany do integracji z SQL Server 7.0. Ponieważ ADP jest silnie związane z OLE DB dla SQL Servera, możesz go użyć tylko z SQL Server 7.0 lub SQL Server 6.5 z zainstalowanym Service Pack 5. Jeżeli chcesz użyć ADP razem z SQL Server 6.5, SP 5, powinieneś przeczytać uwagi do programu Office 2000 i wykonać plik poleceń SQL na serwerze przed rozpoczęciem pracy z ADP i SQL Serverem 6.5. Wady i zalety ADP Gdy rozpatrujesz korzyści płynące z użycia ADP zamiast plików MDB, spójrz na plusy i minusy. Korzyści używania ADP są następujące: ? Używając ADP, możesz zmieniać strukturę tabel w Accessie, nie możesz tego robić, używając tabel z serwera jako tabel połączonych. ? Z ADP masz tylko jedno połączenie do bazy dla wszystkich Twoich obiektów. Używając plików MDB, masz wiele połączeń. Przykładowo, używając tabeli połączonej, formatka z 10 formantami posiada 10 połączeń do bazy danych. Używając ADP, jest tylko jedno połączenie. ? ADP jest łatwe w użyciu. ? ADP umożliwiają użycie Accessa jako narzędzia do projektowania aplikacji. Wadami ADP są: ? ADP ogranicza Cię do używania tylko MS SQL Servera, nie możesz użyć tego typu projektu z bazami Oracle lub Sybase. ? ADP jest nową technologią, a każda nowa technologia może jeszcze nie być dopracowana. ? Nie możesz tworzyć żadnych lokalnych tabel ani zapytań. Po przeanalizowaniu plusów i minusów i przeczytaniu tego rozdziału powinieneś wiedzieć wszystko, co jest Ci potrzebne, aby stwierdzić, czy chcesz użyć ADP w Twoich aplikacjach. Użycie ADP Aplikacja ADP jest aplikacją Accessa 2000 z rozszerzeniem ADP. Używa ona serwera SQL jako silnika bazy danych. Aby móc użyć ADP, musisz zainstalować serwer SQL na Twoim komputerze lub mieć dostęp poprzez sieć do innego serwera SQL. Aby zainstalować lokalną wersję serwera SQL dla Windows 95/98, postępuj według wskazówek w instrukcji instalacji SQL Server 7.0. Jeżeli nie posiadasz SQL Server 7.0, zainstaluj program Microsoft Data Engine (MSDE), który jest lokalną wersją serwera SQL pozbawioną interfejsu użytkownika. Znajduje się on na dysku instalacyjnym Office 2000 w katalogu /SQL. Tworzenie ADP Aby utworzyć ADP, uruchom Access i wybierz Plik|Nowy z głównego menu. Na ekranie pojawi się okno dialogowe, jak na rysunku 15.1, w którym wybieramy typ tworzonej aplikacji. Do wyboru masz: Baza danych|Projekt (istniejąca baza danych) i Projekt (nowa baza danych). Rysunek 15.1. Okno dialogowe Nowy Gdy wybierzesz Baza danych, utworzysz zwykły plik MDB, który używa silnika bazy danych Jet. Wybranie Projekt (istniejąca baza danych), spowoduje utworzenie ADP komunikującego się z istniejącą bazą danych na serwerze SQL. Gdy wybierzesz Projekt (nowa baza danych), rozpoczniesz tworzenie ADP i nowej bazy danych na serwerze. Utwórz przykładowy projekt oparty o istniejącą bazę danych. Podwójne kliknięcie ikony spowoduje wyświetlenie okna dialogowego, w którym określa się położenie pliku ADP. Wygląd tego okna pokazany jest na rysunku 15.2. Po utworzeniu pliku ADP, zostaniesz zapytany o informacje dotyczące bazy danych i serwera SQL, tak jak pokazane jest to na rysunku 15.3.Pamiętasz, że gdy używałeś Data Links (w rozdziale 7., „Zaawansowane ADO”), musiałeś podać nazwę serwera, nazwę użytkownika, hasło oraz nazwę bazy danych, której chciałeś użyć. Do naszego przykładu użyjesz bazy danych „Northwind” w wersji na serwer SQL, która jest dostarczana razem z SQL Server 7.0. Po podłączeniu do bazy danych pojawi się okno projektu z kilkoma nowymi elementami w oknie bazy danych. Okno to jest pokazane na rysunku 15.4. Rysunek 15.2. Określanie położenia pliku Rysunek 15.3. Tworzenie połączenia do bazy danych Rysunek 15.4. Nowe okno bazy danych dla ADP Jeżeli chcesz analizować ten przykład na swoim komputerze, upewnij się, że masz zainstalowany SQL Server 7.0. Możesz zainstalować lokalną wersję serwera SQL wraz z bazą Northwind z dysku instalacyjnego Office 2000. Nowe okno bazy danych Okno bazy danych dla plików ADP jest inne od tego dla plików MDB (porównaj z rysunkiem 15.4). Nowe okno wyświetla następujące elementy: tabele, widoki, procedury przechowywane, diagramy baz danych, formularze, raporty, strony, makra i moduły. W tabela 15.1 został opisany każdy element okna bazy danych. Tabela 15.1. Okno obiektów bazy danych dla ADP Element Opis Tabele Lista wszystkich tabel w bazie danych serwera SQL. W przeciwieństwie do tabel połączonych, możesz dodawać, zmieniać i usuwać tabele bezpośrednio na serwerze Widoki Lista widoków w bazie danych serwera SQL. Możesz dodawać, zmieniać i usuwać widoki bezpośrednio na serwerze Diagramy bazy danych Lista diagramów bazy danych na serwerze. Możesz tworzyć diagram takimi samymi narzędziami jakie są w Visual InterDev 6.0 Formularze Formularze Accessa w Twojej aplikacji. Formularze są zapisane w pliku ADP, a nie na serwerze. Mogą być połączone z tabelami, widokami i procedurami przechowywanymi Raporty Raporty Accessa w Twojej aplikacji. Raporty są zapisane w pliku ADP, a nie na serwerze. Mogą być połączone z tabelami, widokami i procedurami przechowywanymi Strony Strony dostępu do danych aplikacji. Nie są one zapisane na serwerze, ale istnieją jako pliki HTML na dysku (zajrzyj do rozdziału 26. „Użycie stron dostępu do danych”). Mogą być połączone z tabelami, widokami i procedurami przechowywanymi Makra Wszystkie Twoje makra. Makra zapisane są w pliku ADP Moduły Moduły Accessa. Moduły są zapisane w pliku ADP Praca z ADP i istniejącymi bazami danych serwera SQL W czasie pracy nad projektem ADP może być potrzebne dodawanie, zmienianie i usuwanie obiektów bazy danych. W rozdziale tym opiszę, w jaki sposób można manipulować obiektami serwera SQL istniejącymi w Twoim projekcie. Praca z tabelami ADP nie tworzy połączeń do tabel bazy danych tak jak tradycyjne aplikacje Accessa, lecz posiada bezpośredni dostęp do tabel serwera SQL z okna bazy danych. Gdy usuwasz tabelę lub zmieniasz jej nazwę w Accessie, usuwasz ją lub zmieniasz jej nazwę również na serwerze. Chociaż jest to bardzo wygodne, może być niebezpieczne. Powinieneś upewnić się, że ustawiłeś odpowiednie mechanizmy zabezpieczeń serwera SQL tak, aby ograniczyć dostęp użytkowników do tabel. Jeżeli chcesz zmienić strukturę tabeli, naciśnij przycisk Projektuj, co spowoduje otwarcie okna edytora struktury tabel, jak jest to pokazane na rysunku 15.5. Rysunek 15.5. Edytor tabel serwera SQL w Accessie 2000 Edytor struktury tabel serwera SQL jest bardzo podobny to edytora tabel w Accessie. Należy podać nazwę kolumny i jej atrybuty. W tabeli 15.2 zestawione są wszystkie dostępne atrybuty kolumn. Tabela 15.2. Atrybuty w edytorze struktury tabel serwera SQL Nazwa atrybutu Opis ColumnName Nazwa kolumny. Musi być prawidłową nazwą kolumny dla serwera SQL DataType Typ danych kolumny. Dostępne typy danych przedstawione są poniżej Length Długość kolumny Precision Dokładność kolumny. Używane dla kolumn numerycznych Scale Skala (ilość miejsc po przecinku). Używane dla kolumn numerycznych Allow Nulls Znacznik określający, czy kolumna może zawierać puste wartości Default Value Wartość domyślna dla kolumny Identity Znacznik określający, czy kolumna jest kolumną identyfikatora. W tabeli może istnieć tylko jedna kolumna identyfikatora Identity Seed Wartość początkowa kolumny identyfikatora Identity Increment Liczba, o którą jest zwiększana wartość identyfikatora Is RowGuid Znacznik określający, czy kolumna identyfikatora jest GUID Zestawienie typów danych serwera SQL: ? Binary ? Nvarchar ? Bit ? Real ? Char ? Smalldate ? Datatime ? Smallint ? Decmil ? Smallmoney ? float ? Text ? Image ? Timestamp ? Int ? Tinyint ? Money ? Uniqueidentifier ? nchar ? Varbinary ? ntext ? Varchar ? Numeric Widoki w serwerze SQL Używając sekcji Widoki w oknie bazy danych, można administrować widokami serwera SQL. Jedną z największych zalet korzystania z ADP jest to, że możesz utworzyć widok w Accessie i zapisać go na serwerze. Aby utworzyć widok, kliknij przycisk Nowy. Pojawi się edytor widoków serwera SQL, jak widać to na rysunku 15.6. Wygląda znajomo? Powinno, ponieważ został utworzony na wzór sławnego edytora QBE Accessa. Rysunek 15.6. Edytor widoków serwera SQL Gdy jest uruchomiony edytor, można pokazać listę tabel, wybierając Kwerenda|Pokaż tabelę z głównego menu. Zostanie uruchomione okno z listą tabel i widoków, z którego można przeciągnąć obiekty do edytora (rysunek 15.7). Dla każdej tabeli można połączyć pola, tak jak w QBE. Naciśnięcie przycisku SQL pokaże treść zapytania w SQL-u, tak jak pokazane jest to na rysunku 15.8. Użycie podglądu SQL jest przydatne, jeżeli chcesz nauczyć się SQL-a lub chcesz wstawić wyrażenie SQL do kodu programu. Rysunek 15.7. Edytor widoków serwera SQL z tabelami Rysunek 15.8. Edytor widoków serwera SQL z podglądem wyrażenia SQL Możesz użyć kolumny Criteria do zdefiniowania warunków, aliasów kolumn, grupowania i sortowania. Po utworzeniu widoku należy go zapisać przed uruchomieniem, ponieważ jest to obiekt istniejący na serwerze. Procedury przechowywane Wszystkie procedury przechowywane na serwerze SQL mogą być zarządzane przez Accessa. Po wejściu w sekcję procedur przechowywanych można dodać, modyfikować, zmienić nazwę lub usunąć procedurę. Aby dodać procedurę przechowywaną, wybierz przycisk Nowy w oknie bazy danych. Pojawi się edytor procedur przechowywanych Accessa pokazany na rysunku 15.9. Rysunek 15.9. Edytor procedur przechowywanych Accessa Chociaż edytor procedur przechowywanych wygląda bardzo prosto, wyniki jego pracy mogą być bardzo efektywne. Możesz utworzyć każdą poprawną procedurę przechowywaną Transact SQL bezpośrednio w Accessie i zapisać ją na serwerze SQL. Aby uruchomić procedurę przechowywaną należy kliknąć dwa razy. Jeżeli procedura posiada parametr, Access „zapyta” o jego wartość (rysunek 15.10). Rysunek 15.10. Parametr procedury przechowywanej Diagramy bazy danych Prawdopodobnie najbardziej interesującą opcją ADP są diagramy bazy danych. Dla tych, którzy nie znają narzędzi baz danych firmy Microsoft, a które są teraz częścią ADP, wyjaśniam, że diagramy bazy danych umożliwiają zarządzanie i projektowanie tabel bazy danych w sposób wizualny. Baza danych „Northwind” w wersji na serwer SQL ma utworzony diagram powiązań. Diagram ten przedstawia zależności w bazie danych oraz pozwala na zmiany powiązań, modyfikację tabel oraz na dodawanie lub usuwanie kolumn bezpośrednio w oknie edytora diagramu. Aby edytować diagram bazy danych, kliknij go dwa razy, a zostanie on pokazany na ekranie jak na rysunku 15.11. Rysunek 15.11. Diagram bazy danych serwera SQL Możesz przesuwać i zmieniać rozmiary tabel za pomocą myszki. Możesz także powiększyć fragment diagramu, aby ograniczyć widok do określonych tabel. Najlepsze jest to, że możesz wydrukować cały diagram jako dokumentację. Poprzez kliknięcie prawym klawiszem myszki możesz wybrać podgląd atrybutów kolumn i masz dzięki temu dostęp do edytora struktury tabeli (rysunek 15.12)! Rysunek 15.12. Diagram bazy danych serwera SQL z pokazanymi atrybutami kolumn Formularze, strony, raporty i moduły Użycie formularzy, stron, raportów i modułów nie różni się niczym od użycia tych obiektów w plikach MDB, z tą różnicą, że teraz obiekty bazy danych są obiektami serwera SQL, a nie obiektami Accessa. Zarządzanie serwerem SQL poprzez ADP Chociaż nie ma miejsca w tej książce na szczegółowy opis administrowania serwerem SQL, powinieneś wiedzieć, że można zarządzać bazą danych na serwerze poprzez aplikację ADP. Aby zarządzać serwerem, użytkownik ADP musi posiadać właściwe prawa dostępu do serwera SQL. Musisz nadać użytkownikowi ADP prawa administratora bazy danych. Zapewne, do zarządzania serwerem będziesz chciał stworzyć oddzielny projekt ADP. Twoja aplikacja może administrować następującymi obszarami: ? Składowanie i odtwarzanie. ? Replikacja. ? Bezpieczeństwo. Składowanie i odtwarzanie Aby sporządzić kopię bieżącej bazy danych, wybierz Narzędzia|Narzędzia bazy danych| Kopia zapasowa z głównego menu. Access, „zapyta” Cię o miejsce, gdzie ma zapisać kopię, tak jak wygląda to na rysunku 15.13. Rysunek 15.13. Kopia zapasowa serwera SQL wykonywana przez Accessa Baza danych zostanie zapisana w formacie czytelnym dla normalnej procedury odtwarzania serwera SQL. Możesz także wybrać Narzędzia|Narzędzia bazy danych|Przywróć z głównego menu, aby przywrócić bazę danych z kopii zapasowej. Replikacja serwera SQL W Accessie można utworzyć nowe publikacje, synchronizować repliki oraz rozwiązywać konflikty. Aby utworzyć nową publikację, wybierz Narzędzia|Replikacja|Utwórz publikację z głównego menu. Na ekranie pojawi się okno replik, pokazane na rysunku 15.14. Wybierz bazę danych na diagramie i kliknij przycisk Twórz publikację. Uruchomiony zostanie kreator publikacji pokazany na rysunku 15.15. Rysunek 15.14. Okno dialogowe repliki Rysunek 15.15. Kreator publikacji serwera SQL Po uruchomieniu kreatora stosuj się do jego zaleceń, aby utworzyć publikację. Całkiem łatwo tworzy się publikację, a nawet mamy możliwość utworzenia subskrybenta w postaci pliku MDB korzystającego z silnika bazy danych Jet (więcej informacji znajdziesz w rozdziale 22. „Replikacja i JRO”). Aby zsynchronizować bazę danych z repliką, wybierz: Narzędzia|Replikacja|Synchronizuj z głównego menu. Można również tak skonfigurować serwer SQL, aby automatycznie wykonywał synchronizację w określonym przez nas czasie przy użyciu programu Enterprise Manager. Bezpieczeństwo Za pomocą Accessa 2000 można zarządzać mechanizmami bezpieczeństwa serwera SQL poprzez wybranie Narzędzia|Zabezpieczenia|Zabezpieczenia bazy danych. Uruchomione zostanie okno dialogowe zarządzania prawami dostępu użytkownika, bardzo podobne do używanego w Accessie (rysunek 15.6). Za jego pomocą można dodawać, usuwać i edytować użytkowników, ich prawa dostępu do bazy, oraz tworzyć grupy użytkowników. Rysunek 15.16. System zabezpieczeń w Accessie 2000 oparty jest o system zabezpieczeń w SQL Server 7.0 Zwykle użytkownik, który jest właścicielem bazy danych, ma nazwę DBO, natomiast użytkownik – gość nazywa się Guest. Role są identyczne z rolami w SQL Server, użytkownik może mieć np. rolę „Administrator systemu”. Aby dowiedzieć się więcej o systemie bezpieczeństwa, zajrzyj do książek elektronicznych dostarczonych z SQL Server. Powtórne przyłączenie do bazy serwera SQL Co się stanie, gdy po utworzeniu aplikacji ADP chciałbyś zainstalować ją u użytkownika w innej sieci komputerowej? Aby aplikacja prawidłowo działała, musisz zsynchronizować plik ADP tak, aby przyłączył się do właściwej bazy danych. Jak omawialiśmy w rozdziale 7., używałeś uniwersalnych połączeń danych do zarządzania ciągiem połączeniowym OLE DB w ADO. Poprzez ustanowienie odwołania do komponentu Microsoft OLE DB ServiceComponent 1.0 Type Library, w sposób pokazany na rysunku 15.17, możesz użyć interfejsu automatyzacji UDL do synchronizacji aplikacji ADP z właściwą bazą danych. Rysunek 15.17. Ustanowienie odwołania do komponentu OLE DB Service Po ustanowieniu odwołania można przypisać ciąg połączeniowy do metody PromptNew obiektu DataLink. Następnie możesz przypisać ten ciąg do metody CurrentProject.OpenConnection, aby aplikacja ADP przyłączyła się do nowej bazy danych. Fragment programu z wydruku 15.1 przedstawia, w jaki sposób można wykonać taką operację. Wydruk 15.1. Uaktualnianie połączenia ADP Sub UpdateConnection() ' Procedura używa interfejsu UDL Automation ' do utworzenia obiektu połączenia ' i użycia tego połączenia do synchronizacji ADP ' Autorzy: Forte, Howe, Ralston Dim strConnect As String Dim rst As ADODB.Recordset ' Odwołanie do Microsoft UDL Dim udl As MSDASC.DataLinks On Error GoTo Proc_Err ' Tworzenie obiektu Data Link Set udl = New MSDASC.DataLinks StrConnect = udl.PromptNew ' Pobranie informacji o połączeniu z UDL i synchronizacja ADP CurrentProject.OpenConnection strConnect Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub W CurrentProject.Connection ADP używa obiektu MSDataShape OLE DB oprócz SQL Server OLE DB. Spotkałem się z tym, że niektóre funkcje ADO działają nieco inaczej w VB, gdy używa się SQL Server OLE DB bez MSDataShape. Szukaj w Microsoft KnowledgeBase opisu użycia kodu Accessa 2000 w Visual Basic. Tworzenie projektu opartego na nowej bazie danych W tym rozdziale pokażemy, w jaki sposób użyć narzędzi ADP, aby utworzyć od początku nową bazę danych. Utworzymy prostą aplikację, która pokaże nam, jak duże możliwości posiada ADP. Uruchom Access 2000 i wybierz z menu Plik|Nowy, a następnie wybierz z okna dialogowego Nowa baza danych. Access uruchomi kreatora baz danych serwera SQL (rysunek 15.18). Kreator poprosi o podanie nazwy serwera, nazwy użytkownika i jego hasła oraz nazwy bazy danych. Po podaniu tych informacji Access utworzy na serwerze bazę danych. Teraz jesteś gotowy do tworzenia aplikacji. Rysunek 15.18. Kreator bazy danych SQL Tworzenie tabel Chcemy utworzyć prosty system śledzenia wykonywania zadań. Aby to zrealizować, potrzebujemy kilku tabel. Aby utworzyć tabelę, kliknij Utwórz tabelę w widoku projektu w oknie bazy danych. Zauważ, że jesteś od razu pytany o nazwę tabeli, ponieważ obiekt ten istnieje na serwerze i musi być zgodny z wymaganiami serwera. Rysunek 15.19. Okno wyboru nazwy tabeli A teraz utwórz dwie tabele w edytorze, tblWydanie i tlkpTypTransakcji. Opis tblWydanie znajduje się w tabeli 15.3 a tlkpTypTransakcji w tabeli 15.4. Tabela 15.3. Projekt tabeli tblWydanie Nazwa kolumny Typ danej Opis IDWydania Int(4) Klucz główny, identyfikator IDTypTransakcji Int(4) Będzie kluczem obcym Komentarz Text(16) Tabela 15.3. Projekt tabeli tblWydanie (ciąg dalszy) Nazwa kolumny Typ danej Opis DataZapisu Datetime Domyślna wartość: getdate() DataZakończenia Datetime Kolumna może być pusta Tabela 15.4. Projekt tabeli tlkpTypTransakcji Nazwa kolumny Typ danej Opis IDTypTransakcji Int(4) Klucz główny, identyfikator OpisTransakcji Varchar(50) Ustawienie właściwości tabeli i indeksów Aby ustawić indeksy oraz właściwości tabeli wybierz Widok|Właściwości z głównego menu. Uruchomi się okno dialogowe pokazane na rysunku 15.20. W tym oknie można ustawić atrybuty indeksu takie jak: unikatowość, poziom wypełnienia, czy jest indeksem grupowym (CLUSTERED) czy nie. Poprzez edytor struktury tabel ustawiłeś klucz główny, więc istnieje już dla niego unikatowy indeks. Rysunek 15.20. Właściwości tabeli Tworzenie zależności na diagramie bazy danych Teraz, gdy masz utworzone dwie tabele (to było TAKIE proste), powinieneś zdefiniować zależności pomiędzy nimi. Tworzenie zależności pomiędzy tabelami jest bardzo proste przy użyciu ADP. Aby wizualnie zdefiniować związki pomiędzy tabelami za pomocą diagramu bazy danych, przejdź do sekcji Diagramy bazy danych w oknie bazy danych i dodaj nowy diagram. Aby wyświetlić listę tabel, wybierz Widok|Pokaż tabele z głównego menu. Następnie przeciągnij dwie tabele z okna Pokaż tabelę na diagram, jak widać na rysunku 15.21. Aby utworzyć relację, przeciągnij pole z tblkTypTransakcji do tblWydanie. Przeciągnięcie pola spowoduje otwarcie okna relacji (rysunek 15.22), które pozwoli na określenie pól wchodzących w skład zależności. Po ustanowieniu zależności zapisz diagram. Pamiętaj, możesz go użyć jako dokumentację do Twojego projektu. Rysunek 15.21. Tryb edycji diagramu bazy danych Rysunek 15.22. Właściwości relacji Tworzenie kaskad poprzez wyzwalacze SQL Server 7.0 nie zapewnia kaskadowego uaktualniania i kaskadowego kasowania poprzez więzy integralności. Jeżeli chcesz skorzystać z tego mechanizmu, musisz zrobić to, wykorzystując wyzwalacze. Aby utworzyć lub edytować wyzwalacz, kliknij prawym przyciskiem na nazwę tabeli w oknie bazy danych i wybierz Wyzwalacze z menu kontekstowego. Uruchomi się okno dialogowe pokazane na rysunku 15.23. Jeżeli wyzwalacz już istnieje, wybierz go lub kliknij przycisk Nowa, aby utworzyć nowy wyzwalacz. Rysunek 15.23. Zarządzanie wyzwalaczami Tworzenie widoków Zamierzasz utworzyć widok na serwerze SQL, który przedstawia wszystkie zakończone transakcje. Aby utworzyć widok, wybierz Nowy w oknie bazy danych i przeciągnij dwie tabele do edytora, tak jak to jest pokazane na rysunku 15.24. Utworzyłeś prosty widok, który jest wynikiem zapytania SQL przedstawionego na wydruku 15.2 Rysunek 15.24. Edytor widoków Wydruk 15.2. Prosty widok SELECT tlkpTypTransakcji.OpisTransakcji, tblWydanie.IDWydania, tblWydanie.Komentarz, tblWydanie.DataZapisu, tblWydanie.DataZakończenia FROM tblWydanie INNER JOIN tlkpTypTransakcji ON tblWydanie.IDTypTransakcji = tlkpTypTransakcji.IDTypTransakcji WHERE (tblWydanie.DataZakończenia IS NOT NULL) Tworzenie procedur przechowywanych Aby utworzyć procedurę przechowywaną, otwórz edytor procedur i wpisz odpowiednie wyrażenie TSQL. Utworzymy prostą procedurę, która wybierze jedną transakcję określoną przez jej numer. Kod procedury pokazany jest na wydruku 15.3. Wydruk 15.3. Prosta procedura przechowywana Create Procedure "WybierzTransakcje" @NumerWyd int As SELECT tlkpTypTransakcji.OpisTransakcji, tblWydanie.IDWydania, tblWydanie.Komentarz, tblWydanie.DataZapisu, tblWydanie.DataZakończenia FROM tblWydanie INNER JOIN tlkpTypTransakcji ON tblWydanie.IDTypTransakcji = tlkpTypTransakcji.IDTypTransakcji WHERE tblWydanie.IDWydania=@NumerWyd Tworzenie aplikacji w Accessie Aby przekonać się, jak łatwo tworzy się aplikacje w Accessie, używając ADP, spójrz na prosty formularz pokazany na rysunku 15.25. Jest on związany z tabelą tblWydanie i za jego pomocą można wpisywać i przeglądać dane, filtrować, itp., tak samo jak w zwykłym pliku MDB. Tworzenie raportów jest równie proste jak w Accessie 97. Po prostu uruchom kreatora i utwórz swój raport. Rysunek 15.25. Nasza formatka Tworzenie plików ADE W Accessie 97 wprowadzono w życie nowy pomysł, pliki MDE. Jest to skompilowana i zablokowana wersja pliku MDB. W Accessie 2000 masz możliwość tworzenia plików MDE dla aplikacji MDB oraz plików ADE dla plików ADP. Aby utworzyć plik ADE, wybierz Narzędzia|Narzędzia bazy danych|Utwórz plik ADE, jak widać to na rysunku 15.26. Po wybraniu lokalizacji pliku Access utworzy tam plik ADE. Od teraz wszystkie formularze, raporty, strony i moduły będą zablokowane dla użytkownika aplikacji. Zakończenie: przenoszenie bazy danych Access 97 na serwer SQL i do pliku ADP We wcześniejszych wersjach Accessa kreator rozbudowy bazy danych nie był doskonały. Potrafił przenieść tabele na serwer SQL i to wszystko. Zapytania pozostawały w Accessie i były uruchamiane na tabelach połączonych, co było bardzo nieefektywne. Jeżeli jednak uruchomisz tego samego kreatora z Accessa 2000, otrzymasz dużo lepsze rezultaty. Kreator zamieni wszystkie „widoki” dla silnika bazy Jet oraz zapytania typu SELECT na widoki serwera SQL, a także procedury Accessa na procedury przechowywane (jeżeli będzie to możliwe). Następnie zostanie utworzona aplikacja ADP oparta o serwer SQL. Mimo że jeszcze jest wiele ograniczeń, kreator ten jest wart zainteresowania; w najgorszym razie pomoże Ci rozpocząć pracę nad przeniesieniem bazy. Jest on bardzo prosty w użyciu, więc wybierz Narzędzia|Narzędzia bazy danych|Kreator rozbudowy. Rysunek 15.26. Tworzenie pliku ADE Rozdział 16. Tworzenie interfejsu użytkownika dla Microsoft SQL Server W tym rozdziale: ? Architektura klient-serwer: OLE DB kontra ODBC. ? Tworzenie połączenia z serwerem SQL. ? Procedury przechowywane i kwerendy przekazujące. ? Raportowanie z serwera SQL w Accessie. ? Formularze w aplikacji. ? Zaawansowane właściwości: dostawca OLE DB dla SQL serwera. ? Wykonywanie poleceń z parametrami. ? Użycie klasy Connection. Od czasu wprowadzenia na rynek Microsoft Access jest uważany za wspaniałe narzędzie do tworzenia interfejsu użytkownika dla zewnętrznych baz danych. Mimo że Access 2000 ma kilka wspaniałych nowych właściwości do pracy z SQL Server 7.0 poprzez Projekty programu Access (ADP), właściwości te nie działają dobrze z SQL Server 6.5 i nie działają wcale poprzez połączenie ODBC. W tym rozdziale pokażemy, jak tworzyć aplikacje oparte na SQL Server 6.5 lub Sybase System 10. W rozdziale 17., „Interfejs Accessa 2000 do Oracle” pokażemy, jak tworzyć aplikacje oparte na Oracle Enterprise Server. Architektura klient-serwer: OLE DB kontra ODBC Systemem klient-serwer nazywamy system, który używa serwera bazy danych (np. SQL Server lub Oracle) do przechowywania danych oraz aplikacji klientów, które komunikują się z bazą danych (systemy trójwarstwowe, o których się dużo mówi, mają podobną architekturę za wyjątkiem tego, że logika biznesowa umieszczona jest w oddzielnej logicznej warstwie). Aplikacja Accessa typu MDB połączona z serwerem SQL jest w rozumieniu tej architektury klientem. Access, gdy używa połączenia ODBC, ładuje silnik bazy Jet, który pośredniczy w komunikacji z bazą danych. Aplikacja typu ADP we współpracy z serwerem SQL używa nowszej technologii OLE DB, która komunikuje się z serwerem bez ładowania silnika Jet. Chociaż podejście OLE DB ma wiele znaczących plusów, jego największą wadą jest brak wsparcia dla innych serwerów SQL niż SQL Server. Mimo że ODBC i pliki MDB nie są tak szybkie jak nowe projekty ADP, są jednak użyteczne i dosyć wydajne, co pokażemy w tym rozdziale. Tworzenie połączenia z serwerem SQL Aby rozpocząć pracę z bazą danych na serwerze SQL, należy zestawić z nią połączenie. Ponieważ będziemy używać połączenia ODBC do komunikacji z bazą, upewnijmy się, że na komputerze, którego używamy, zainstalowany jest właściwy sterownik. Standardowa instalacja Accessa 2000 instaluje sterownik ODBC do SQL Server (jeżeli chcesz użyć Sybase SQL Server, musisz zainstalować właściwy dla niego sterownik ODBC, którego nie ma jednak na płycie z Office 2000). Po zainstalowaniu Accessa 2000 ze sterownikiem ODBC jesteś już gotowy do pracy z serwerem SQL. Istnieją dwie metodologie dostępu do danych: tabele połączone oraz kwerendy przekazujące. Większość aplikacji używa obydwu metod. Aby użyć tych metod, najpierw musisz utworzyć systemowe źródło danych ODBC. Tworzenie źródła danych ODBC (DSN) Systemowe DSN jest miejscem, gdzie zapisujesz wszystkie informacje o połączeniach ODBC. Każdy DSN posiada unikatową nazwę, której używają aplikacje. Aby utworzyć DSN na Twoim komputerze, wykonaj następujące czynności. 70. Uruchom Źródła danych ODBC (32 bity) z Panelu sterowania, na zakładce Systemowe DSN naciśnij Dodaj. Gdy uruchomi się okno dialogowe DSN wybierz SQL Server i naciśnij przycisk Zakończ. Uruchomi się kreator tworzenia DSN, taki jak na rysunku 16.1. Rysunek 16.1. Tworzenie nowego źródła danych w Panelu sterowania 71. Na pierwszej stronie kreatora (rysunek 16.1) wprowadź unikatową nazwę DSN (np. NorthWind), ewentualny opis i nazwę serwera, na którym uruchomiony jest serwer SQL. Naciśnij Dalej, gdy wprowadziłeś te informacje. 72. Na drugiej stronie wprowadza się informacje o systemie użytkowników. Gdy chcesz użyć zwykłego systemu serwera SQL (lub gdy nie wiesz, jaki chcesz wybrać), zaznacz Uwierzytelnianie serwera SQL, używając ID logowania i hasła podanego przez użytkownika, wpisz nazwę użytkownika oraz hasło i naciśnij przycisk Dalej (używając domyślnego użytkownika na SQL Server, nazwa użytkownika to „SA”, a hasło jest puste). 73. Trzecia strona kreatora pokazana jest na rysunku 16.2. Wprowadzasz na niej nazwę bazy danych, do której chcesz się dołączyć. W celu pokazania przykładów w tym rozdziale przyłączymy się do bazy NorthWind. Rysunek 16.2. Wybór domyślnej bazy danych podczas tworzenia DSN 74. Czwarta strona zawiera opcje specyficzne dla ODBC, jak śledzenie. Zatwierdź domyślne opcje i naciśnij Zakończ. 75. Ostatnia strona pozwala na sprawdzenie nowo utworzonego połączenia. Dobrze jest sprawdzić tutaj połączenie i w wypadku niepowodzenia testu, wprowadzić od razu poprawki. Teraz jesteś gotowy do użycia serwera SQL w aplikacji Access 2000. Łączenie tabel Aby zacząć pracę z nowo utworzonym źródłem danych ODBC, najczęściej stosowanym i najłatwiejszym rozwiązaniem jest połączenie tabel serwera SQL z plikiem MDB. Tym sposobem możesz uruchamiać proste zapytania SQL, aby np. wypełnić pola listy. Dla naprawdę małych tabel można nawet podłączyć formularze bezpośrednio do tabeli i w ten sposób umożliwić użytkownikom wprowadzanie danych (więcej informacji o łączeniu formularzy do danych z serwera SQL znajdziesz w części tego rozdziału zatytułowanej „Formularze w aplikacji”). Aby dołączyć tabele poprzez ODBC, wykonaj następujące czynności. 76. Upewnij się, że istnieje prawidłowe źródło danych (zajrzyj do „Tworzenie źródła danych ODBC (DSN)”). 77. Otwórz bazę danych Access i wybierz z menu: Plik|Pobierz dane zewnętrzne|Połącz tabele. 78. Na ekranie pojawi się lista wszystkich źródeł danych ODBC. Wybierz ten DSN, na którym chcesz pracować, i naciśnij OK. 79. Access wyświetli teraz listę tabel, które możesz dołączyć (rysunek 16.3). Gdy wybierzesz tabele, możesz zapisać razem z nimi hasło dostępu do bazy danych. Gdy to zrobisz, użytkownicy aplikacji nie będą musieli podać tego hasła podczas pierwszego uruchomienia aplikacji. Rysunek 16.3. Wybór tabel z bazy danych ODBC 80. Teraz Access łączy tabele z plikiem MDB. Nazwy tabel poprzedzone zostaną prefiksem „dbo_”, ponieważ właścicielem tabel w SQL Server jest „Database Owner” (właściciel bazy danych). 81. Gdy w tabeli serwera SQL nie ma zdefiniowanego klucza głównego, Access nie może połączyć takich tabel w trybie odczytu i zapisu, więc daje Ci możliwość utworzenia lokalnego unikatowego indeksu w sposób pokazany na rysunku 16.4. Jeżeli użyjesz tego mechanizmu, będzie można zapisywać do tabeli, a Jet 4.0 będzie utrzymywał indeks na Twoim komputerze. Rysunek 16.4. Tworzenie unikatowego identyfikatora rekordu Po połączeniu tabel możesz tworzyć kwerendy, formularze i raporty odnoszące się do tych połączonych tabel. Wady tabel połączonych Łączenie tabel ze źródeł danych ODBC do Accessa może być bardzo nieefektywne i niebezpieczne. Silnik Jet musi pośredniczyć w całej komunikacji pomiędzy serwerem SQL a aplikacją. Jeżeli nie może użyć unikatowego indeksu na serwerze, może wczytać wszystkie rekordy tabeli do przetwarzania na komputerze klienta. Wyobraź sobie taką sytuację. Łączysz tabelę z 5 milionami rekordów, tworzysz zapytanie wybierające około 500 rekordów, ale warunek selekcji nie opiera się o żaden unikatowy indeks. W zależności od projektu tabeli serwer SQL może zwrócić całe 5 milionów rekordów do posortowania przez silnik Jet! Jeżeli uruchomisz to na niezbyt szybkim komputerze, będzie to trwało godzinami. Aby wydobyć całą moc z serwera SQL, powinieneś użyć procedur przechowywanych. Procedura przechowywana na serwerze SQL jest podobna do pytania zapisanego w Accessie. Jest to skompilowane wyrażenie SQL, które pobiera parametry i zostanie wykonana na serwerze. Wielu programistów wysyła wyrażenia SQL do serwera, ponieważ jest to o wiele szybsze niż użycie tabel połączonych. Metoda ta jest jednak wolniejsza od procedur przechowywanych, ponieważ procedura posiada utworzony podczas kompilacji plan wykonania tak, aby zapytanie wykonywało się z największą możliwą prędkością. Użycie procedur przechowywanych daje najlepsze wyniki przy zaangażowaniu najmniejszym wysiłku. Oprócz zwiększenia prędkości procedury przechowywane zmniejszają ruch w sieci. Wysyłasz do serwera tylko małe 1 kB polecenia uruchomienia procedury zamiast dużego 100 kB lub większego nieskompilowanego wyrażenia SQL. W obu przypadkach serwer odsyła Ci tylko te dane, których potrzebujesz. Połączenie najlepszych metod: wypełnianie tabel podczas startu aplikacji Ponieważ zwykle używam procedur przechowywanych jako podstawowej metody manipulacji danymi w moich aplikacjach klient-serwer, zwykle używam tabel połączonych do wypełniania list i list rozwijanych danymi wykorzystywanymi na formatkach i raportach. Aby uzyskać najlepszą wydajność, możesz przy starcie aplikacji tworzyć kopie tabel serwera do tabel lokalnych. Oczywiście, używaj tej techniki tylko do danych statycznych (nie zmieniających się zbyt często). Technika ta, chociaż bardzo użyteczna, nie jest dostępna w projektach ADP, które były omawiane w rozdziale 15. „Wprowadzenie do projektów programu Microsoft Access oraz narzędzi wizualnych”, ponieważ lokalne tabele opierają się o silnik Jet, a ADP w ogóle go nie ładuje. Procedury przechowywane i kwerendy przekazujące Dobrze jest oprzeć raporty Accessa na procedurach przechowywanych, ponieważ są one szybkie i efektywne. Problem stanowi to, że nie możesz połączyć się z procedurą tak jak, łączysz się z tabelą na serwerze SQL. Możesz jednak użyć kwerendy przekazującej, aby uzyskać te same możliwości. Kwerenda przekazująca to wyrażenie SQL wysłane do przetworzenia przez serwer SQL. Silnik Jet nie przetwarza takiego wyrażenia, a Access otrzymuje od serwera wyniki. Kwerendy przekazujące umożliwiają wykorzystanie całej mocy obliczeniowej serwera bazy danych. Tworzenie procedur przechowywanych wykracza poza ramy tej książki, jednak jeżeli utworzysz widok w projekcie ADP (zajrzyj do rozdziału 15.), możesz skopiować wyrażenie z okna podglądu SQL i wstawić je do procedury przechowywanej. Wydruk 16.1 przedstawia przykład procedury przechowywanej z bazy danych NorthWind, która zwraca informacje o zamówieniach z zadanego zakresu dat. Wydruk 16.1 tworzy procedurę przechowywaną sp_OrdersByDate, która wymaga dwóch argumentów, @StartDate i @EndDate. Wydruk 16.1. Prosta procedura przechowywana CREATE PROCEDURE dbo.sp_OrdersByDate @StartDate datetime, @EndDate datetime AS SELECT Customers.CustomerID, Customers.CompanyName, Orders.OrderDate, [Order Details].Quantity, [Order Details].UnitPrice, Quantity*UnitPrice AS TotalAmount FROM Customers INNER JOIN Orders ON Customers.CustomerID=Orders.CustomerID INNER JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID Where OrderDate Between @StartDate and @EndDate Uruchomienie procedury przechowywanej jest proste. Logujemy się do bazy danych i wpisujemy polecenie EXECUTE w oknie SQL. Jeżeli procedura wymaga parametrów, należy je podać. Aby uruchomić procedurę sp_OrdersByDate (wydruk 16.1) za pomocą narzędzia SQL Server T/SQL, powinieneś wpisać takie polecenie: Execute sp_OrdersByDate @StartDate='07/01/94' , @EndDate='09/30/94' Wynik działania procedury sp_OrdersByDate pokazany jest na rysunku 16.5. Procedura ta zwraca zamówienia klientów uporządkowane według dat wraz z wartością każdego zamówienia. Tworzenie raportów opartych na procedurach przechowywanych poprzez zapytania przekazujące Aby uruchomić procedurę przechowywaną w zapytaniu przekazującym, należy użyć polecenia Execute, która została wcześniej omówiona. Możesz utworzyć kwerendę przekazującą poprzez wybranie z menu: Kwerenda|Wyłącznie SQL|Przekazująca, po przejściu do trybu projektowania zapytań (rysunek 16.6). Rysunek 16.5. Wynik działania procedury przechowywanej Rysunek 16.6. Tworzenie kwerendy przekazującej Nie możesz używać tabeli QBE do tworzenia kwerend przekazujących, musisz wpisywać wyrażenie SQL bezpośrednio do okna SQL. Należy używać składni SQL zgodnej ze składnią bazowego serwera (w tym rozdziale używamy składni Microsoft SQL Server 6.5, ale będziemy musieli użyć innej w rozdziale 17. „Interfejs Accessa 2000 do Oracle”, w którym zajmiemy się bazą Oracle). Po wpisaniu wyrażenia SQL musisz utworzyć ciąg połączeniowy ODBC. Ciąg ten „mówi” Accessowi, do której bazy danych ma wysłać wyrażenie SQL. Należy otworzyć okno właściwości i ustawić właściwość Ciąg połączenia ODBC. W Accessie dostępny jest konstruktor uruchamiany przez naciśnięcie przycisku „...” obok pola właściwość. Możesz samemu wpisać prawidłowy ciąg połączenia lub uruchomić konstruktor i wybrać właściwe źródło danych ODBC z zainstalowanych w systemie, tak jak pokazane jest na rysunku 16.7. Zapisz kwerendę przekazującą jako qsptOrdersbyDate. Zauważ, że kwerenda przekazująca ma inną ikonę niż normalna kwerenda (jak widać na rysunku 16.8). Rysunek 16.7. DSN zainstalowane w systemie Rysunek 16.8. Zapisana kwerenda przekazująca Raportowanie z serwera SQL w Accessie Jeżeli spytasz doświadczonych programistów, co lubią najbardziej w Accessie, wielu z nich odpowie, że ma on jeden z najlepszych modułów raportowych. Access umożliwia łatwe tworzenie wspaniałych raportów bardzo szybko, nawet jeżeli dane nie pochodzą z tabel Accessa. Możliwość łatwego raportowania z danych ODBC sprawia, że Access jest dobrym wyborem dla całego raportowania w przedsiębiorstwie. Można tworzyć raporty na wiele sposobów. Najprostszą metodą jest połączenie tabeli ODBC i utworzenie kwerendy w Accessie jako bazy dla raportu. Mimo że jest to najszybszy sposób stworzenia raportu, nie jest polecany ze względów opisanych dalej w tym rozdziale. Zwykle komputery, które służą za serwery baz danych SQL, są dużo szybsze i posiadają więcej pamięci RAM niż średni komputer w biurze. Prześledzę sposoby na zwiększenie wydajności raportów klient-serwer, aby w pełni skorzystać z mocy serwerów, na których zainstalowana jest baza danych. Kolejne przykłady będą oparte o przykładową bazę danych „NorthWind” dostarczaną z SQL Server. Aby uruchomić raport oparty na kwerendzie przekazującej, uruchom Kreator raportów i wybierz kwerendę przekazującą qsptOrdersbyDate. Utwórz teraz taki raport, jaki potrzebujesz. Przykład gotowego raportu pokazywany jest na rysunku 16.9. Zapisz gotowy raport jako qsptOrdersbyDate. Rysunek 16.9. Raport oparty o procedurę przechowywaną Zaawansowane możliwości: przekazywanie parametrów do procedury przechowywanej w czasie działania programu Jesteś przyzwyczajony do tworzenia kwerend z parametrami na potrzeby raportów w Accessie, które wymagają podania przez użytkownika dat lub innych wartości. W Accessie, jeżeli użyjesz pola formularza w warunku kwerendy, możesz zapytać użytkownika o parametr, jak jest to pokazane na rysunku 16.10. Przy użyciu procedur musisz powtórnie utworzyć polecenie Execute z nowymi parametrami wewnątrz kwerendy przekazującej qsptOrdersbyDate za każdym razem, gdy uruchamiasz raport. Na formatce służącej do wprowadzania parametrów, pokazanej na rysunku 16.10, oprogramowane jest zdarzenie Click tak, aby ustawić właściwą postać wyrażenia Execute w kwerendzie i uruchamia procedurę z nowym zakresem dat. Kod, który to realizuje, zamieszczony jest na wydruku 16.2. Zauważ, że potrzebujesz odwołania do DAO 3.6 w aplikacji. Aby ustawić to odwołanie, otwórz główny moduł i z głównego menu w edytorze VBE wybierz Tools|References. W oknie dialogowym zaznacz bibliotekę DAO 3.6 Object Library. Wydruk 16.2. Zmiana wyrażenia SQL i uruchomienie raportu Private Sub cmdPrint_Click() ''''''''''''''''''''''''''''''''''''''' ' Przeznaczenie: Zmiana kodu SQL, aby wywołać ' procedurę przechowywaną z nowymi parametrami '''''''''''''''''''''''''''''''''''''''' Dim db DAO.Database Dim strSql As String Rysunek 16.10. Formularz pobierania parametrów do uruchomienia raportu On Error GoTo Click_Err StrSQL = "Execute sp_OrdersbyDate @StartDate=" & _ Chr(39) & Me.txtStartDate & Chr(39) & _ ", @EndDate=" & Chr(39) Me.txtEndDate & Chr(39) Set db = CurrentDb Db.QueryDefs("qsptOrdersbyDate").SQL = strSQL DoCmd.OpenReport "qsptOrdersbyDate", acViewPreview Click_Exit: Exit Sub Click_Err: MsgBox Err.Description Resume Click_Exit End Sub Dodatkowe filtrowanie danych raportu Czasami warunek Where w procedurze przechowywanej nie zapewnia dokładnie tych informacji, których potrzebujesz. Możesz dostać 500 zamówień i chcesz odfiltrować je, określając minimalną wartość zamówienia. Access dostarcza dwóch metod do filtrowania raportów poprzez metodę DoCmd.OpenReport: można podać nazwę zapisanej kwerendy lub przekazać warunek Where do raportu. Rysunek 16.10 przedstawia formatkę wprowadzania wartości parametrów, która umożliwia także przekazanie wartości do filtra, bazującego na wartości zamówienia, oprócz wprowadzenia zakresu dat. Jeżeli użytkownik zdecyduje się na użycie filtra oprócz zakresu dat, wykonany zostanie kod wywołujący metodę BuildCriteria z obiektu Application. Prawidłowym filtrem będzie np.: OrderAmount>500. Metoda BuildCriteria utworzy prawidłowy filtr, który następnie będzie zastosowany podczas wykonania metody DoCmd.OpenReport. Wydruk 16.3 zawiera kod, który zarówno zmienia wyrażenie SQL w zapytaniu przekazującym, jak i tworzy filtr. Wydruk 16.3. Użycie metody BuildCriteria do założenia filtra w raporcie Function BuildWhere(curAmt As Currency) As String ' Tworzy warunek Where za pomocą metody BildCriteria BuildWhere = BuildCriteria( "TotalAmount", dbCurrency, ">=" & curAmt) End Function Private Sub cmdPrint_Click() ''''''''''''''''''''''''''''''''''''''' ' Przeznaczenie: Zmiana kodu SQL, aby wywołać ' procedurę przechowywaną z nowymi parametrami ' oraz dodaje możliwość filtrowania. ' Filtrowanie jest realizowane poprzez właściwość ' Where Clause metody DoCmd.OpenReport '''''''''''''''''''''''''''''''''''''''' Dim db DAO.Database Dim strSql As String On Error GoTo Click_Err StrSQL = "Execute sp_OrdersbyDate @StartDate=" & _ Chr(39) & Me.txtStartDate & Chr(39) & _ ", @EndDate=" & Chr(39) Me.txtEndDate & Chr(39) Set db = CurrentDb Db.QueryDefs("qsptOrdersbyDate").SQL = strSQL ' Tutaj sprawdzamy, czy jest potrzebny filtr ' tzn. czy jest zaznaczone pole wyboru if Me.chkFilter Then 'Zastosuj filtr DoCmd.OpenReport "qsptOrdersbyDate", acViewPreview, , _ BuildWhere(Me.txtFilter) Else DoCmd.OpenReport "qsptOrdersbyDate", acViewPreview End If Click_Exit: Exit Sub Click_Err: MsgBox Err.Description Resume Click_Exit End Sub I na koniec niezłym pomysłem jest drukowanie w nagłówku raportu informacji o filtrze oraz jego wartości. Dodatkowo powinieneś ostrzegać użytkownika o pustym raporcie za pomocą zdarzenia raportu NoData. Fragment programu, który to realizuje, jest na wydruku 16.4. Wydruk 16.4. Kod w raporcie obsługujący filtr oraz zdarzenie NoData Private Sub Report_NoData(Cancel As Integer) ' Brak danych! On Error Resume Next ' Ostrzegaj użytkownika o pustym raporcie MsgBox "Ten raport nie zawiera danych" & vbNewLine & _ "Proszę podać inny warunek", vbCritical, Me.Name ' Nie otwieraj tego raportu Cancel = True End Sub Private Sub Report_Open (Cancel As Integer) On Error Resume Next ' Sprawdź, czy zastosowano filtr If Forms!frmPrintReport!chkFilter Then ' Wpisz w nagłówku raportu warunek filtra Me.lblFilter.Caption = _ "Raport filtrowany według zamówień > " & _ Forms!frmPrintReport!txtFilter Me.lblFilter.Visible = True End If End Sub Formularze w aplikacji Formularze są zwykle centralną częścią aplikacji Accessa. Nie inaczej jest, gdy używasz Accessa jako interfejsu do serwera SQL. Możesz użyć formularzy w dwóch trybach – związanym i niezwiązanym. Formularze związane Jest możliwe oparcie formularzy na procedurach przechowywanych, jednak wtedy możliwy jest tylko odczyt. Jeżeli Twoi użytkownicy są przyzwyczajeni do formularzy związanych, a ty chcesz użyć ich zamiast tabel połączonych, to nie ma nic do zrobienia, poza napisaniem zapytania, które ograniczy ilość rekordów wyświetlanych na formularzu. Używając formularza związanego opartego na procedurze przechowywanej i zapytaniu przekazującym powinieneś zmieniać parametry procedury przed otwarciem formularza (identycznie jak na wydruku 16.2). Jeżeli masz dużą ilość danych lub chcesz modyfikować dane, użyj ADO i formularzy niezwiązanych w sposób opisany w następnych częściach tego rozdziału. Formularze niezwiązane Gdy używasz formularzy związanych, tracisz sporo czasu na ich obsługę, szczególnie w wypadku dołączonych tabel. W czasie obsługi dołączonych tabel Jet musi zarządzać komunikacją ODBC. Dodatkowo tworzone są połączenia do bazy oddzielnie do każdego formantu, co zużywa sporo czasu i pamięci na obsługę. Dobrą alternatywą jest zastosowanie formularzy niezwiązanych. W niezwiązanych formularzach możesz zapytać użytkownika o klucz główny lub inną szukaną wartość, a następnie otworzyć zestaw rekordów w ADO i wypełnić pola edycyjne znalezionymi wartościami, tak jak pokazane jest na rysunku 16.11. Rysunek 6.11. Formularz niezwiązany Możesz wypełnić listę rozwijalną za pomocą kwerendy przekazującej opartej na procedurze przechowywanej i użyć kodu przedstawionego na wydruku 16.5 do obsługi zdarzenia After Update. Wydruk 16.5. Wypełnianie formularza zawarością obiektu recordset Private Sub cboFind_AfterUpdate() ' Ta funkcja pobierze rekord, bazując na wartości klucza głównego ' i wypełni wartości w niezwiązanym formularzu Dim conn As ADODB.Connection Dim rst As ADODB.Recordset Dim strSQL As String On Error GoTo Proc_Err DoCmd.Hourglass False Set rst = New ADODB.Recordset Set conn = New ADODB.Connection ' Tworzę wyrażenie SQL, bazując na aktualnej ' wartości pola listy rozwijalnej strSQL = "Select * from Categories Where CategoryID=" & Me.cboFind ' Tworzenie połączenia ADO do serwera SQL With conn .Provider = "SQLOLEDB" .ConnectionString = "data source=pawel;user id=sa;" & _ "initial catalog=NorthWindCS" ' Tryb tylko do odczytu .Mode = adModeRead .Open End With ' Otwórz Recordset rst.Open strSQL, conn ' Wypełnij wartości Me.CategoryID = rst!CategoryID Me.CategoryName = rst!CategoryName ' Zamknij połączenie rst.Close conn.Close Set conn = Nothing Set rst = Nothing Proc_Exit: DoCmd.Hourglass False Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Gdy zaczniesz tworzyć niezwiązane formularze, będziesz chciał zmieniać, kasować dane oraz wykonywać inne operacje w ADO. Poniżej opiszemy, jak używać ADO oraz OLE DB dla serwera SQL. Zaawansowane właściwości: dostawca OLE DB dla serwera SQL Aby użyć dostawcy OLE DB dla serwera SQL, musisz upewnić się, czy jest on zainstalowany na komputerze. W trakcie standardowej instalacji Accessa 2000 instalowany jest także dostawca OLE DB do SQL Server. Po zainstalowaniu dostawcy możesz używać obiektu połączenia. Aby ustawić obiekt połączenia (ang.: connection), należy użyć składni przedstawionej na wydruku 16.6. Wydruk 16.6. Podłączanie do serwera SQL przez OLE DB Sub SQLServer() ' Procedura podłączenia do serwera SQL Dim conn As ADODB.Connection Set conn = New ADODB.Connection With conn .Provider = "SQLOLEDB" .ConnectionString = "data source=(local);" & _ "user id=sa;initial catalog=NorthWindCS" .Mode = adModeRead .Open End With MsgBox "Połączony z " & conn.Provider, vbInformation End Sub Następny zestaw wyników Jedną z właściwości serwera SQL, której nie dało uzyskać się przy użyciu technologii Jet, jest wykonywanie dwóch wyrażeń SQL jak jednego. Używając tej właściwości, możesz kilkakrotnie wykonywać wyrażenie SQL zwracające różne zestawy rekordów, używając jednego obiektu Recordset. Aby to zrobić, użyj metody NextRecordset. Wydruk 16.7. Użycie NextRecordset Sub NextRst(strCustomerId As String) ' Użyj ALFKI lub ANTON dla przykładu ' Procedura używa jednego obiektu Recordset dwa razy Dim cmd As ADODB.Command Dim conn As ADODB.Connection Dim rst As ADODB.Recordset Dim strSQL As String Set conn = New ADODB.Connection ' Podłączenie do serwera SQL With conn .Provider = "SQLOLEDB" .ConnectionString = "data source=(local);" & _ "user id=sa;initial catalog=NorthWindCS" .Mode = adModeRead .Open End With ' Wyrażenie SQL zwracające dwa zestawy wyników ' Możesz to uruchomić tylko na serwerze, który ' wspiera wielokrotne zestawy wyników strSQL = "Select * From Customers Where CustomerID=" & _ Chr(39) & strCustomerId & Chr(39) strSQL = strSQL & vbNewLine strSQL = strSQL & "Select * From Orders Where CustomerID=" & _ Chr(39) & strCustomerId & Chr(39) Set cmd = New ADODB.Command With cmd .CommandText = strSQL .ActiveConnection = conn .CommandType = adCmdText End With Set rst = cmd.Execute ' Otwarcie pierwszego zestawu wyników Do Until rst.EOF Debug.Print rst!CompanyName rst.MoveNext Loop ' Pobierz następny zestaw Set rst = rst.NextRecordset Do Until rst.EOF Debug.Print rst!OrderDate rst.MoveNext Loop rst.Close conn.Close Set rst = Nothing Set cmd = Nothing Set conn = Nothing End Sub Wykonywanie poleceń z parametrami Wcześniej, w rozdziale 1., kładłem nacisk na korzyści z użycia procedur przechowywanych w aplikacji, wszędzie tam, gdzie jest to możliwe, aby wykorzystać szybkość wykonania i zmniejszenie ruchu w sieci. Teraz gdy wykorzystujemy ADO, użycie procedur przechowywanych daje te same korzyści. W ADO, gdy używasz obiektów poleceń dostawcy OLE DB dla serwera SQL, można odwzorować ten obiekt na procedurę przechowywaną i przekazywać do niej parametry poprzez obiekty parametrów. Jak większość rzeczy w ADO, można zrobić to na kilka sposobów. W dalszej części rozdziału prześledzimy najczęstsze sposoby użycia procedur przechowywanych i obiektów poleceń, jednak musisz sam stwierdzić, który najlepiej pasuje do Twojego stylu programowania. Ja postaram się przekazać moje komentarze, aby pomóc Ci w tych wyborach. Długa droga Najlepiej rozpocząć od najbardziej pracochłonnej metody wykonywania procedur. Chociaż nikt nie będzie chciał pracować w taki sposób, można nauczyć się kilku rzeczy. Po pierwsze, docenisz inne metody wykonywania procedur, a po drugie, zrozumiesz zależności pomiędzy obiektami Connection, Command i Parameter, których będziesz używał w swoich programach. Aby uruchomić polecenie z parametrem, musisz utworzyć obiekt Command i Parameter, a następnie dołączyć obiekt Parameter do Command (patrz wydruk 16.8). Wydruk 16.8. Wykonanie polecenia z parametrem Sub ExecuteCommandwithParms() ' Procedura uruchamia procedurę przechowywaną z parametrami Dim conn As ADODB.Connection Dim cmd As ADODB.Command Dim prm As ADODB.Parameter Set conn = New ADODB.Connection ' Zestawienie połączenia z bazą danych With conn .Provider = "SQLOLEDB" .ConnectionString = "data source=(local);" & _ "user id=sa;initial catalog=NorthWindCS" .Open End With ' Utworzenie i inicjalizacja obiektu Connection Set cmd = New ADODB.Command With cmd .ActiveConnection = conn .CommandText = "byroyality" .CommandType = adCmdStoredProc End With ' Utworzenie i inicjalizacja obiektu parameter Set prm = New ADODB.Parameter With prm .Name = "@percentage" .Direction = adParamInput .Type = adInteger .Value = 50 End With cmd.Parameters.Append prm ' Otwarcie obiektu Recordset z wykonanego polecenia Dim rst As ADODB.Recordset Set rst = cmd.Execute ' odczytanie wszystkich rekordów wyniku Do Until rst.EOF Debug.Print rst!au_id rst.MoveNext Loop ' Zakończenie rst.Close conn.Close Set rst = Nothing Set conn = Nothing Set cmd = Nothing Set prm = Nothing End Sub Użycie metody CreateParameters Prostą metodą obsługi procedur przechowywanych bez pisania dużej ilości kodu jest użycie metody CreateParameter obiektu Command. Metoda ta nie zmusza Cię do tworzenia obiektu dla każdego parametru aktualnego procedury przechowywanej, co zmniejsza ilość kodu, szczególnie, jeżeli procedura ma wiele parametrów. Uważam tę metodę za najmniej uciążliwą do programowania i najbardziej niezawodną do uruchamiania poleceń na SQL Server 6.5 i 7.0. Jak widać na wydruku 16.9, użycie metody CreateParameter tworzy obiekty parametrów bez dodatkowego kodu. Wydruk 16.9. Wykonanie polecenia bez obiektu parametru Sub ExecuteCommandwithCreateParms() ' Wykonanie procedury przechowywanej ' przy użyciu metody CreateParameter Dim conn As ADODB.Connection Dim cmd As ADODB.Command Set conn = New ADODB.Connection ' Zestawienie połączenia z bazą danych With conn .Provider = SQLOLEDB .ConnectionString = "data source=(local);" & _ "user id=sa;initial catalog=NorthWindCS" .Open End With ' Utworzenie i inicjalizacja obiektu Connection Set cmd = New ADODB.Command With cmd .ActiveConnection = conn .CommandText = "byroyality" .CommandType = adCmdStoredProc ' Utworzenie informacji parametrów ' używamy metody CreateParameter obiektu ' command, aby uprościć program .Parameters.Append .CreateParameter("@Percentage", _ adInteger, adParamInput, , 50) End With ' Otwarcie wyniku wykonania procedury Dim rst As ADODB.Recordset Set rst = cmd.Execute ' Odczytanie wszystkich rekordów wyniku Do Until rst.EOF Debug.Print rst!au_id rst.MoveNext Loop ' Zakończenie rst.Close conn.Close Set rst = Nothing Set conn = Nothing Set cmd = Nothing End Sub Użycie Refresh Użycie metody Refresh ze zbioru parametrów obiektu Command jest bardzo podobne do użycia metody CreateParameter, poza tym, że nie musisz tworzyć żadnego obiektu parametru. Zamiast tego, po podłączeniu do bazy ustawiasz obiekt Command na procedurę przechowywaną i odświeżasz zbiór parametrów. Operacja ta zwróci zbiór parametrów gotowych do wypełnienia. Metoda ta pozwala na dużą elastyczność (można tworzyć ogólne obiekty poleceń), jednak na razie na 100 procent działa jedynie z SQL Server 7.0. Używając SQL Server 6.5, napotkałem kilka problemów, które spowodowały, że poczekam z użyciem Refresh na następne wersje ADO. Nawet mimo tych ograniczeń powinieneś poznać składnię i sposób użycia metody Refresh do użycia z SQL Server 7.0 i kolejnymi wersjami ADO. Ważną rzeczą, o której należy pamiętać, jest to, że program wykonuje dodatkowe operacje na bazie danych w czasie wykonania metody Refresh, aby odczytać informacje o parametrach. Mimo prostoty użycia należy zawsze sprawdzić wydajność tego rozwiązania. Wydruk 16.10. Użycie metody Refresh obiektu Command Sub ExecuteCommandwithParmRefresh() ' Wykonanie procedury przechowywanej bez tworzenia ' obiektów Parameter. Pomocne przy procedurach ' z dużą ilością parametrów Dim conn As ADODB.Connection Dim cmd As ADODB.Command Set conn = New ADODB.Connection ' Zestawienie połączenia z bazą danych With conn .Provider = SQLOLEDB .ConnectionString = "data source=(local);" & _ "user id=sa;initial catalog=NorthWindCS" .Open End With ' Utworzenie i inicjalizacja obiektu Connection Set cmd = New ADODB.Command With cmd .ActiveConnection = conn .CommandText = "byroyality" .CommandType = adCmdStoredProc ' W tym przykładzie używamy metody Refresh, ' która pobiera parametry z serwera. ' Po jej wykonaniu wypełniamy parametry ' i wykonujemy procedurę. Unikamy tworzenia ' i dołączania parametrów .Parameters.Refresh .Parameters("@Percentage").Value = 50 End With ' Otwarcie wyniku wykonania procedury Dim rst As ADODB.Recordset Set rst = cmd.Execute ' Odczytanie wszystkich rekordów wyniku Do Until rst.EOF Debug.Print rst!au_id rst.MoveNext Loop ' Zakończenie rst.Close conn.Close Set rst = Nothing Set conn = Nothing Set cmd = Nothing End Sub Obsługa zwracanych wartości Czasami procedura przechowywana zwraca wartość, która świadczy o prawidłowym lub nieprawidłowym wykonaniu procedury. Może ona również zwrócić wartość identyfikatora nowo dodanego rekordu. W każdym wypadku będziesz chciał znać wartość zwracaną. ADO pozwala na pobranie wartości zwracanych poprzez odczytanie zbioru parametrów po wykonaniu polecenia. Na wydruku 16.11 przedstawiony jest program, który wykonuje bardzo prostą procedurę przechowywaną, zwracającą po prostu wartość 55. Procedura wygląda następująco: CREATE PROCEDURE sp_CmdWithParm AS /* Wartość zwracana */ Return 55 Po wykonaniu polecenia możesz odczytać wartość zwracaną z zestawu parametrów, po użyciu metody Refresh (popatrz poprzedni akapit), identyfikując ją przez numer kolejny wartości zwracanej, tak jak tutaj: cmd.Parameters(0).Value Wydruk 16.11. Pobieranie wartości zwracanej Sub CommandReturnValues() ' Procedura uruchamia procedurę przechowywaną ' i odczytuje zwracaną wartość ' Treść procedury przechowywanej: ' CREATE PROCEDURE sp_CmdWithParm AS ' /*Wartość zwracana*/ ' Return 55 Dim conn As ADODB.Connection Dim cmd As ADODB.Command Set conn = New ADODB.Connection Set cmd = New ADODB.Command ' Zestawienie połączenia z bazą danych With conn .Provider = SQLOLEDB .ConnectionString = "data source=(local);" & _ "user id=sa;initial catalog=NorthWindCS" .Open End With ' Utworzenie i inicjalizacja obiektu command With cmd .ActiveConnection = conn .CommandText = "sp_CmdWithParm" .CommandType = adCmdStoredProc .Parameters.Refresh End With cmd.Execute MsgBox "Wartość zwracana: " & cmd.Parameters(0).Value conn.Close Set conn = Nothing End Sub Wykonanie procedury bez obiektu Command Procedury z parametrami, które zwracają wiersze tabeli, można uruchomić bez używania obiektu Command. Aby to wykonać, należy utworzyć wyrażenie SQL i użyć metody open obiektu Recordset. rst.open 'exec sp_SimpleProc @OrderID=1', conn Użycie klasy Connection Gdy Twoja aplikacja coraz bardziej zależy od napisanego kodu, powinieneś zacząć przyzwyczajać się do pisania kodu ogólnego i nadającego się do powtórnego użycia. W tej książce postaram się pokazać Ci możliwie dużo przykładów programowania klas. Tworzenie obiektu klasy Connection jest jednym z najważniejszych przykładów, które chciałbym Ci pokazać. Jest to klasa do natychmiastowego użycia nie tylko w Accessie, ale także w każdym programie obsługującym VBA, włączając inne aplikacje Office 2000 oraz Visual Basic 5 i 6. Gdy programujesz w ADO, powinieneś przyzwyczaić się do korzystania z klasy Connection. Na podstawie tej ogólnej klasy tworzy się obiekt połączenia ADO. Gdy cały kod odpowiedzialny za dostęp do danych opiera się na tej szczególnej klasie tworzącej połączenie do bazy, musisz utrzymywać małe fragmenty kodu odpowiedzialne za informacje o połączeniu. W tym rozdziale utworzysz prostą klasę DBConnection, która będzie miała jedną publiczną metodę, Connect. Connect jest prostą funkcją VBA, która zwraca obiekt ADO Connection. Funkcja zamieszczona na wydruku 16.12 tworzy obiekt ADO Connection i ustawia wartość zwracaną na utworzony obiekt (Klasa Connection jest bardzo prosta. Możesz rozszerzyć ją tak, aby używała pliku UDL, jak jest opisane w rozdziale 7. „Zaawansowane ADO”). Wydruk 16.12. Prosta klasa Connection Function Connect() As ADODB.Connection ' Komponent do wielokrotnego użycia. Tworzy połączenie ' z bazą danych. Możesz użyć tego komponentu, aby ' zcentralizować miejsce, gdzie są ustawiane informacje o ' bazie danych Dim conn As ADODB.Connection Set conn = New ADODB.Connection ' Informacje o połączeniu się z bazą With conn .Provider = "SQLOLEDB" .ConnectionString = "data source=(local); user id=sa;" & _ "initial catalog=airline" .Open End With Set Connect = conn End Function Użycie klasy Connection w aplikacji Użycie klasy Connection w aplikacji jest proste. Gdziekolwiek chcesz podłączyć się do bazy danych, tworzysz obiekt DBConnection, aby utworzył dla Ciebie obiekt ADO Connection, jak widać to na wydruku 16.13. Pozwoli to na ukrycie specyficznego dla procesu połączenia kodu w ogólnej nadającej się do powtórnego wykorzystania klasie lub obiekcie COM do późniejszego wykorzystania. Wydruk 16.13. Użycie klasy Connection Sub UseConnect() ' Używa komponentu Connection, aby podłączyć się do bazy Dim conn As ADODB.Connection Dim oConnect As DBConnection Set oConnect = New DBConnection Set rst = oConnect.Connect End Sub Rozdział 17. Interfejs Accessa 2000 do Oracle'a W tym rozdziale: ? Dostęp do danych Oracle'a przez Accessa ? Funkcje w Oracle'u i Accessie ? Poznajemy widoki i procedury przechowywane ? Tworzenie niezwiązanego interfejsu do Oracle'a Na przekór dominacji Oracle'a w aplikacjach tworzonych w Accessie jest mało publikacji na temat ich współpracy. W rozdziale tym chcę wypełnić tę lukę. Mimo że nowe projekty ADP zapewniają możliwość tworzenia wyrafinowanych aplikacji klient-serwer, w wielu przypadkach musisz użyć bogatego środowiska programowania zwykłej aplikacji Accessa. Na przykład w wypadku, gdy tworzysz prototyp aplikacji lub chcesz skorzystać z możliwości zarządzania heterogenicznymi danymi. Oracle jest wyjątkowo potężną i wyrafinowaną bazą danych, więc w tym rozdziale nie możemy przedstawić wszystkich niuansów i jej złożoności. Mimo to, poprzez poznanie prostych technik i wytycznych, możesz wyzwolić jej siłę bez specjalnych kłopotów. Zasadniczo, dobre programowanie Access/Oracle wymaga użycia mechanizmów Oracle'a i pozwolenia mu na zarządzanie danymi, ponieważ właśnie to robi świetnie. Może to brzmi dziwnie, ale w praktyce nie jest to tak proste do zrealizowania. Wielu programistów Accessa zostało zobligowanych do użycia Oracle'a w swoich aplikacjach i często nie inwestują zbyt wiele czasu w udoskonalanie struktury bazy danych, tak jak robią to przy projektowaniu dla Accessa. Często muszą używać mniej optymalnych struktur danych lub hurtowni danych. Dodatkowo, wielu programistów Accessa uważa się za zwolnionych z użycia w swoich aplikacjach czegokolwiek więcej z Oracle'a, niż ODBC i konto użytkownika. W rozdziale tym prześledzimy sposoby ominięcia takich wyzwań, jak również użycia podstawowych narzędzi Oracle'a, które niewielkim nakładem pracy mogą Ci służyć. Dostęp do danych Oracle'a przez Accessa Istnieje kilka sposobów dostępu do danych Oracle'a przez Accessa. W tym rozdziale skupimy się na dwóch: podstawowych technikach ODBC bez programowania dla ODBC oraz programowaniu z użyciem ADO. W czasie powstawania aplikacji możesz korzystać z obu sposobów, jednak w gotowej aplikacji powinieneś używać tylko jednego. Dwie podstawowe techniki dostępu do danych są stosowane na trzy sposoby: ? Łączenie tabel (ODBC). ? Kwerendy przekazujące (SPT) (ODBC). ? Bezpośrednie połączenie poprzez ADO. Tabele połączone Ponieważ w Accessie bardzo prosto tworzy się tabele połączone pochodzące z wielu źródeł danych, większość danych Oracle'a pochodzi z tych właśnie tabel. Tabele połączone używają ODBC, pomimo tego, że podstawowym modelem dostępu do danych w Accessie 2000 jest ADO. Powoduje to konieczność instalowania na komputerze zarówno sterowników ODBC, jak i ADO. Aby utworzyć połączenie z tabelą Oracle'a, musisz posiadać: ? Zgodny z Oracle'em sterownik ODBC. ? Połączenie sieciowe z bazą Oracle poprzez SQLNet lub Net8 (Oracle używa własnego protokołu sieciowego). Bez tych narzędzi nie będziesz w stanie połączyć się z bazą. ? Sterownik ODBC w Accessie. Poprzez ODBC możesz: połączyć się do bazy, pracować z tabelami, widokami i procedurami oraz wysyłać do wykonania wyrażenia SQL. Tworzenie ciągu połączenia ODBC Zarządca ODBC na komputerze klienta komunikuje się pomiędzy Twoim programem a odpowiednim dla Twojego źródła danych sterownikiem ODBC. Aby podłączyć się do bazy Oracle, powinieneś najpierw utworzyć odpowiedni ciąg połączenia ODBC. Ciąg ten składa się z części przedstawionych w tabeli 17.1. Ciąg ODBC może wyglądać następująco: ODBC;DSN=MSOracleDriver;UID=Scott;SERVER=empexample;;TABLE=SCOTT.DEPT Każda część ciągu może być opuszczona, więc jeżeli ciąg nie będzie zawierał potrzebnych informacji, użytkownik będzie musiał je podać. Tabela 17.1. Składniki ciągu połączeniowego ODBC Składnik Opis DSN Nazwa źródła danych UID Nazwa użytkownika PWD Hasło Database Jeśli nazwa DSN nie jest nazwą bazy, należy tutaj wpisać nazwę bazy APP Nazwa aplikacji używającej połączenia Tworzenia nazwy źródła danych Aby przygotować ODBC do pracy z Accessem, powinieneś utworzyć nazwę źródła danych. Jest to bardzo prosta operacja. Poniższe punkty wskażą sposób utworzenia DSN dla Oracle'a. 82. Uruchom administrator ODBC z Panelu sterowania. 83. W programie administratora naciśnij przycisk Nowy, aby dodać źródło danych dla Oracle'a. 84. Wybierz Oracle ODBC Driver, Microsoft ODBC Driver dla Oracle'a lub inny sterownik ODBC dla Oracle'a. Naciśnij Zakończ. W tym miejscu będziesz zapytany o informacje w okienku podobnym do okna z rysunku 17.1. Wygląd tego okna zależy od wybranego sterownika i jego wersji. Rysunek 17.1. Wpisywanie informacji o DSN Po utworzeniu DSN można rozpocząć dołączanie tabel Oracle'a do twojej aplikacji. Koszt połączenia z Oracle'em Tworzenie połączenia z bazą danych Oracle zajmuje dużo więcej czasu i zasobów niż połączenie z bazą Jet. W czasie programowania z użyciem ODBC, RDO, DAO, ODBC Direct lub ADO powinieneś spróbować trzymać cały czas otwarte połączenie do bazy i używać go w aplikacji. Access zajmie się tym, jeżeli połączysz tabelę z Oracle'em. Trzyma on wtedy otwarte połączenie, a Ty możesz go użyć poprzez obiekt Table. Rysunek 17.2 przedstawia, jak można na podstawie tabeli połączonej zbudować kwerendę. Rysunek 17.2. Buduj kwerendy na tabelach połączonych identycznie jak na tabelach lokalnych SELECT SCOTT_EMP.ENAME, SCOTT_DEPT.DNAME FROM SCOTT_DEPT INNER JOIN SCOTT_EMP ON SCOTT_DEPT.DEPTNO= SCOTT_EMP.DEPTNO WITH OWNERACCESS OPTION; Lecz takie podejście jest kosztowne. Gdy uruchamiasz kwerendę na tabeli połączonej, Twoje zapytanie SQL jest zapisane w Accessie, więc Oracle nie wie nic o nim. Sterownik ODBC i Jet muszą zanalizować wyrażenie. Sterownik ODBC analizuje kwerendę i może wysłać przetworzony fragment Twojego zapytania do Oracle'a, zwykle przetwarzając jedną tabelę. Zwykle kończy się to tym, że Oracle wysyła ogromne ilości danych przez sieć do komputera klienta, gdzie są one przetwarzane przez Jet. Ponieważ Jet jest jedyną częścią tego łańcucha, która rozumie naszą kwerendę, całe przetwarzanie odbywa się na komputerze klienta. Może być to niezbędne od czasu do czasu, ale nie jest to działanie prawdziwego systemu klient-serwer. Jeżeli chcesz przeglądać dane lub analizować strukturę tabel, a nie masz narzędzi Oracle'a, tworzenie tabel połączonych jest dobrym sposobem. Łączenie jest również dopuszczalne, jeżeli chcesz dostać dane, które pozostaną w lokalnej tabeli, lub chcesz zadać pytanie do danych pochodzących z wielu źródeł danych (kwerenda heterogeniczna). Jednak, jeżeli zadajesz homogeniczne pytanie do danych Oracle'a, powinieneś pomyśleć o innym podejściu. Kwerendy przekazujące (SPT) Poprzez użycie tego samego połączenia, którego używasz do łączenia tabel, otrzymujesz dostęp do serwera Oracle i przenosisz ciężar wykonania kwerendy na serwer – tam, gdzie powinna być wykonana. Oczywiście w SPT wszystkie źródła danych, do których odwołujesz się w kwerendzie, muszą znajdować się w bazie Oracle oraz wyrażenia SQL muszą być zapisane w dialekcie Oracle, jednak są to małe problemy, jeżeli skonfrontuje się je ze skróconym czasem odpowiedzi oraz zmniejszonym ruchem w sieci. W kwerendach SPT jedyną informacją, jaką przesyłasz poprzez sieć, jest wyrażenie SQL, a jedyną jaką otrzymujesz jest wynik. Aby utworzyć SPT, wykonaj następujące czynności: 85. Utwórz nową kwerendę. 86. Z menu Kwerenda wybierz Tylko SQL. 87. Wybierz Przekazująca. 88. W widoku SQL edytora kwerend (dostępny tylko tryb projektowania) wybierz Widok i Właściwości. 89. Wpisz ciąg połączeniowy ODBC do właściwości Ciąg połączenia ODBC. Ciąg ODBC powinien wyglądać podobnie do takiego: ODBC;DSN=EmpExample;UID=SCOTT;PWD=tiger;DBQ=empexample; Możesz skopiować ciąg z tabeli połączonej. 90. Wpisz wyrażenie SQL. Przykładowe wyrażenie SQL wygląda następująco: Select * from emp W czasie wykonania, Access wysyła to wyrażenie SQL bezpośrednio do Oracle'a poprzez połączenie ODBC. Jet nie jest zaangażowany w jego wykonanie. Oracle odbiera to wyrażenie i po wykonaniu odsyła wynik (jeśli istnieje) do klienta. Niektóre sytuacje gdzie mogą być użyte SPT to: ? Wykonanie wyrażeń SQL zmieniających strukturę bazy. ? Uzyskanie wybranych wierszy i kolumn z tabel Oracle'a. ? Sprawdzenie ilości wierszy zmienionych wyrażeniem Update. ? Dostarczenie źródła rekordów dla prostego formularza związanego pokazującego małą ilość rekordów. ? Utworzenie, zmiana i wykonanie widoków i procedur przechowywanych w Oracle'u. Powinieneś zawsze sprawdzić, czy zastosowanie kwerend SPT ulepszy Twoją aplikację. Określanie właściwości kwerend przekazujących Gdy tworzysz kwerendę przekazującą, musisz ustawić właściwość kwerendy, która określa, czy zwraca ona rekordy, czy nie. Kwerendy, które wstawiają, zmieniają lub kasują rekordy, nie zwracają rekordów, natomiast kwerendy typu Select zwykle to robią. Jeżeli nie ustawisz odpowiednio tej właściwości, dostaniesz komunikat błędu. Składnia kwerend przekazujących Musisz pisać wyrażenia SQL zgodnie ze składnią Oracle'a, która różni się znacznie od składni generowanej przez tabelkę QBE. Access 2000 obsługuje dialekt SQL, który najbardziej odpowiada standardowi ANSI-92, lecz jeżeli używałeś SQL Accessa począwszy od wersji 1.1, przegląd różnic pomoże Ci efektywnie używać bazy Oracle. Oracle nie wymaga zakańczania wyrażenia średnikiem, gdy tworzymy kwerendę przekazywaną, mimo że jest on wymagany w trakcie wykonywania zapytań z programu SQL Plus. Średnik na końcu wyrażenia SQL spowoduje błąd. Nie można używać nawiasów kwadratowych do identyfikacji nazw tabel i kolumn. Ich użycie spowoduje błąd. Mimo że Access zmienia kropkę z SCOTT.EMP na podkreślenie w SCOTT_EMP w trakcie łączenia tabeli, musisz użyć separatora Oracle, którym jest kropka. Wielkość liter Wyrażenia SQL w Oracle'u mogą być pisane zarówno dużymi, jak i małymi literami oprócz porównywanych w frazie Where wartości. Poniższe dwa wyrażenia są takie same: Select eName, job FroM eMP SELECT ENAME, JOB FROM EMP Tylko pierwsze z dwóch poniższych wyrażeń zwróci prawidłową wartość: Select ename, job from EMP where JOB='MANAGER' Select ename, job from EMP where JOB='manager' Wyrażenie Select Słowo kluczowe Select działa tak samo jak w Accesie. Select wskazuje bazie Oracle, które pola (kolumny) zwrócić jako wynik. Nazwy kolumn wymienione po słowie Select muszą istnieć w tabelach wymienionych w następnej klauzuli From. SELECT ename, job, hiredate ... Tabele lub widoki użyte w kwerendzie są wymieniane w klauzuli From, identycznie jak w Accessie. Również identycznie jak w Accessie kolejność tabel w liście nie wpływa na wynik zapytania. Select ename, job, hiredate FROM emp Klauzula WHERE Klauzula Where sprawia większości programistom Accessa sporo problemów na początku pracy z bazą Oracle, ponieważ skupia się tutaj większość różnic pomiędzy SQL Accessa i SQL Oracle. W Oracle'u klauzula Where nie tylko ogranicza ilość rekordów zwracanych przez serwer, jak to jest w Accessie, ale także definiuje zależności pomiędzy tabelami i widokami użytymi w zapytaniu. W tych przykładach znajomych dla większości programistów Accessa klauzula Where ogranicza rekordy w wyniku: Select * from Emp WHERE mng=7698 Select * from EMP WHERE HIREDATE between '1/1/1990' and '1/1/1995' Select * from EMP WHERE ename like 'M%' Definiowanie zależności Gdy w kwerendzie występuje więcej niż jedna tabela, klauzula Where w Oracle'u definiuje zależności. SELECT emp.ename, dept.dname FROM emp, dept WHERE (emp.deptno=dept.deptno) AND (emp.ename like 'M%') Pokazane powyżej wyrażenie zwraca rekordy, które mają te same wartości po obu stronach relacji zdefiniowanej przez pola podane w klauzuli Where (emp.deptno=dept. deptno). Aby zwrócić rekordy, które nie są reprezentowane z obu stron relacji, musisz utworzyć połączenie typu outer join. W Oracle'u połączenie takie tworzy się poprzez wstawienie znaku (+) po tej stronie relacji, która będzie zwracała wartości null, gdy nie ma odpowiadającej wartości. Dobrze jest zapamiętać, że wstawia się znak (+) po tej stronie, która zawierać będzie dodatkowe puste pozycje. Wyrażenie poniżej zawiera połączenie typu outer join z lewej strony relacji. Wyświetli ono wszystkich pracowników, którzy mają przypisaną lub nie nazwę oddziału. SELECT emp.ename, dept.dname FROM emp, dept WHERE emp.deptno(+)=dept.deptno Relacje w Oracle'u mogą być zapisywane jako wyrażenia. Nie jest to możliwe w Accessie. Użycie wyrażeń w relacjach nie jest częste. Może być to potężne narzędzie, gdy pracujemy na nieoptymalnych strukturach danych lub w danych występują szczególne zależności, co zdarza się w hurtowniach danych. Wyrażenie SQL poniżej przedstawia sposób użycia wyrażenia w relacji. Select emp.ename, dept.dname From emp, dept Where (emp.deptno=dept.deptno+10) Użycie znaków specjalnych Access używa * i ? jako znaków specjalnych. Gwiazdka (*) zastępuje dowolną ilość znaków w tekście, natomiast znak zapytania – jeden znak. W Oracle'u istnieją te same możliwości, ale używamy znaku % zamiast *, a _ zastępuje jeden znak. Znaki te mogą być używane w następujący sposób: Select * from emp where ename like 'M%' Select * from emp where ename like 'J__S' Użycie Null i Not Null W Oracle'u testowanie wartości null odbywa się identycznie jak w Accessie. SELECT * FROM emp WHERE comm IS NULL SELECT * FROM emp WHERE comm IS NOT NULL Tworzenie wyrażeń Insert W Accessie kwerenda wstawiająca nowe wartości do tabeli generuje wyrażenie SQL, które wygląda następująco: INSERT INTO SCOTT_EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, DEPTNO) SELECT '9999' AS Expr1, 'JP' AS Expr2, 'SALESMAN' AS Expr3, _ 7698 AS Expr4, #7/27/1997# AS Expr5, 2380 AS Expr6, 10 AS Expr7; Jednak Access dopuszcza klauzulę Values tak samo jak Oracle (patrz poniżej), ale musisz ją wpisać samemu. W Oracle'u możesz uprościć to wyrażenie: INSERT INTO SCOTT_EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, _ COMM, DEPTNO) VALUES ('9999', 'JP', 'SALESMAN', 7698, _ TO_DATE('7/27/1997', 'MM/DD/YYYY'), 2380, 0, 10) Zwróć uwagę jak w Oracle'u używa się To_Date(), aby sprawdzić, czy wpisana data jest prawidłowa. Więcej o tej i innych funkcjach Oracle'a napisałem w dalszej części rozdziału. Tworzenie wyrażeń Update Implementacja wyrażenia Update w SQL Oracle nie różni się wiele od tej z Accessa. Poniżej przedstawione jest wyrażenie SQL, wygenerowane przez QBE Accessa, skojarzone z tabelą połączoną. UPDATE SCOTT_EMP SET SCOTT_EMP.SAL = [7000] WHERE ((([SCOTT_EMP].[EMPNO])=9999)); Wersja dla Oracle'a jest prostsza od wersji Accessa o kilka nawiasów. Ponieważ ODBC wysyła ciąg ODBC bezpośrednio do tabel użytkownika Scott, nie ma potrzeby kwalifikować nazw tabel nazwą użytkownika. UPDATE emp SET SAL = 7000 WHERE empno=9999 Użycie Group By/Having QBE Accessa samo troszczy się o prawidłową składnię, gdy tworzysz kwerendę grupującą. W Oracle'u musisz sam się tym zająć zająć. Tak jak w Accessie, Group By grupuje dane w wymienionych kolumnach. Wszystkie inne kolumny muszą być przeglądane poprzez funkcje agregujące (np.: Sum(), Avg() i inne). SELECT deptno, count(*) FROM emp WHERE deptno<>10 GROUP BY deptno HAVING count(*)<6 Podczas wykonania powyższego wyrażenia Oracle pobierze wszystkie rekordy z wartością pola deptno różną od 10 i grupuje je według pola wymienionego w operacji GROUP BY. Na koniec Oracle przeszukuje rezultat i odrzuca rekordy, których liczba (count(*)) jest większa od 6. Jedyną różnicą pomiędzy tym wyrażeniem SQL a wyrażeniem w SQL Accessa jest występowanie nawiasów. Funkcje w Oracle'u i Accessie W Accessie, przed wykonaniem kwerendy jest ona przeszukiwana pod kątem występowania funkcji zarówno VBA, jak i utworzonych przez Ciebie. Analizator wyrażeń (ang. Jet Expression Service) dopuszcza stosowanie dowolnych funkcji w wyrażeniach SQL. Nie możesz jednak stosować funkcji VBA oraz napisanych przez siebie, gdy używasz kwerend SPT. Powód jest prosty, SPT nie używa w ogóle silnika Jet. Oracle odbiera SQL jako ciąg znaków i musi on być zrozumiały dla Oracle'a. Mimo że jest możliwe utworzenie w Oracle'u podobnego zestawu funkcji jak w Accessie, wykracza to jednak poza ramy tego rozdziału. W dalszej części rozdziału zrobimy przegląd niektórych, najczęściej używanych funkcji Oracle'a, które możesz użyć w kwerendach przekazujących. Wiele z funkcji udostępnianych przez Oracle jest bardzo podobnych do funkcji operujących na ciągach w Accessie. Poniżej przedstawię funkcje, które nie istnieją w Accessie, lub działają inaczej niż podobne do nich. Aby uzyskać pełną listę funkcji, sięgnij do dokumentacji Oracle'a. Ciągi Większość typów danych, z którymi się spotykasz, to ciągi lub takie, które da się zamienić na ciągi. Zwykle będziesz chciał przeszukiwać ciągi znaków, analizować je, zmieniać wielkość liter, łączyć lub inaczej mówiąc zmieniać je tak, aby pasowały do twoich formularzy i raportów. W tej części opiszę niektóre z powszechnie używanych operacji na ciągach znaków, które będziesz chciał wykonać w Oracle'u. Łączenie Oracle łączy ciągi znaków przy użyciu dwóch pionowych kresek (||) w odróżnieniu od Accessa, w którym używa się znaku & lub +. Poniższe wyrażenie przedstawia w jaki sposób, łączyć ciągi. SELECT ename || deptno FROM emp Initcap, Lower, Upper Funkcja Initcap(string) zmienia na wileką pierwszą literę każdego wyrazu ciągu. Podobnie Upper i Lower zmienia wszystkie litery ciągu na odpowiednio wielkie i małe. Select INITCAP(ename) FROM emp Zwróci następujący wynik: INITCAP(ENAME) ---------- Jp Allen Ward Jones Martin Blake Clark Scott King Turner Adams James Ford Miller SELECT UPPER(ENAME) FROM emp Zwróci następujący wynik: UPPER(ENAME) ---------- JP ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER SELECT LOWER(ename) FROM emp Zwróci następujący wynik: LOWER(ENAME) ---------- jp allen ward jones martin blake clark scott king turner adams james ford miller Instr Instr zwraca pozycję znaku, który podałeś jako argument i może być bardzo przydatna, jeżeli chcesz analizować ciągi, poszukując przecinków lub spacji. Jeżeli poszukiwany znak nie występuje w ciągu, zwracana jest wartość 0. Funkcja Instr jest wrażliwa na wielkość liter w odróżnieniu od Accessa. Instr ma cztery parametry: ? String – wymagany. Ciąg znaków lub odwołanie do ciągu, który chcesz przeszukać. ? Set – wymagany. Znak lub ciąg znaków, które chcesz znaleźć. ? Start – nieobowiązkowy. Pozycja, na której powinno się rozpocząć szukanie. Domyślnie jest to pierwsza pozycja. ? Occurrence – nieobowiązkowy. Jeżeli chcesz znaleźć drugie lub trzecie wystąpienie parametru Set, wpisz 2 lub 3. Popatrz na wyrażenie SQL, w którym nie podamy wystąpienia ani pozycji startowej: Select ename, instr(ename, 'A') from emp Wynik: ENAME INSTR(ENAME,'A') ---------- ---------------- JP 0 ALLEN 1 WARD 2 JONES 0 MARTIN 2 BLAKE 3 CLARK 3 SCOTT 0 KING 0 TURNER 0 ADAMS 1 JAMES 2 FORD 0 MILLER 0 Gdy funkcja zostanie wywołana z parametrem Occurence równym 2, znajdzie drugie wystąpienie szukanego znaku. Select ename, instr(ename, 'A') from enp ENAME INSTR(ENAME,'A') ---------- ---------------- JP 0 ALLEN 0 WARD 0 JONES 0 MARTIN 0 BLAKE 0 CLARK 0 SCOTT 0 KING 0 TURNER 0 ADAMS 3 JAMES 0 FORD 0 MILLER 0 LTrim/RTrim Access ma trzy funkcje do wycinania znaków z ciągu: LTrim(), aby usunąć znaki z lewej strony, Rtrim, aby usunąć znaki z prawej strony oraz Trim, aby usunąć znaki z obu stron. Oracle ma tylko Ltrim i Rtrim. Jednak funkcje obcinające znaki w Accessie i Oracle'u różnią się w inny, bardzo ważny sposób. W Accessie funkcje te obcinają tylko spacje, w Oracle'u mogą obcinać dowolny zbiór znaków. Funkcje obcinające mają dwa argumenty: ? String – wymagany. Ciąg lub odwołanie do ciągu, na którym chcesz wykonać operacje. ? Set – nieobowiązkowy. Znaki, które chcesz usunąć. Możesz użyć funkcji LTrim/RTrim, aby usunąć słowo 'THE' z początku tytułów poprzez wykonanie następującego wyrażenia: Select LTrim(Title, '"THE ') from Books Należy pamiętać, że funkcje RTrim/LTrim są niewrażliwe na wielkość liter i ignorują kolejność podanych znaków do usunięcia. Oznacza to, że tytuły książek zostaną zmienione w sposób pokazany w tabeli 17.2. Tabela 17.2. Przed i po obcięciu funkcją LTrim Przed Po obcięciu The Great Access Book Great Access Book How to Develop in Access Ow to Develop in Access The Ethical Developer ical Developer Access 2000 Development Unleashed Access 2000 Development Unleashed Funkcje LTrim/RTrim nie zwracają uwagi na kolejność liter w zbiorze liter do usunięcia ani na to, że powtarza ją się kilka razy (tak jak: THE ETH... w The Ethical Developer). Aby uzyskać prawidłowe wyniki powinieneś prawdopodobnie użyć kombinacji tej funkcji z Instr, Substr i Decode, aby dostać wyniki, jakich naprawdę potrzebujesz. Soundex Od roku 1988 Census Bureau używa algorytmu klasyfikacji nazwisk, które są podobnie wymawiane (w języku angielskim). Algorytm ten nazywany jest Soundex. Działa on przez pobranie pierwszej litery i przypisanie liczby do każdej następnej spółgłoski. Różne spółgłoski mają przyporządkowane te same wartości (na przykład [T] i [D] są tłumaczone na 3), oparte o ich brzmienie. Proces ten jest powtarzany aż do skompletowania 4. cyfrowego kodu. Słowa, które mają za mało spółgłosek – są uzupełniane zerami tak, aby wygenerować czteroznakowy kod. Samogłoski są odrzucane, chyba że jest ona pierwszym znakiem w słowie. Kody Soundex wyglądają następująco: Select ename, soundex(ename) from emp ENAME SOUNDEX(ENAME) ---------- -------------- JP J100 ALLEN A450 WARD W630 JONES J520 MARTIN M635 BLAKE B420 CLARK C462 SCOTT S300 KING K520 TURNER T656 ADAMS A352 JAMES J520 FORD F630 MILLER M460 Soundex może być użyteczny do wyszukiwania nazwisk w listach lub tytułach. Wyrażenie SQL takie jak poniżej: Select ename from emp where soundex(ename) like soundex('muller') powinno zwrócić nazwiska takie jak: Mailer Miller Molar Moller Muler Mulronsky Funkcja Soundex nie interpretuje kontekstu znaków, więc niektóre wyniki mogą nie być intuicyjne na pierwszy rzut oka. Słowa o różnej długości mogą sobie odpowiadać według tego algorytmu. Mimo tych niedogodności można go użyć do przeszukiwania list wysyłkowych i książek telefonicznych. Substr Substr można porównać do funkcji Mid w Accessie. Oracle nie ma bezpośredniego odpowiednika funkcji Right() i Left() znanych z Accessa. Tak jak funkcja Accessa Mid(), Substr() pobiera trzy argumenty: ? String – ciąg lub odwołanie do ciągu ? Start – podana jawnie lub obliczona pozycja początku podciągu ? End – podana jawnie lub obliczona wartość reprezentująca ilość znaków po prawej stronie pozycji Start W sytuacjach, kiedy nazwisko klienta występuje w postaci: MacIntyre, Alastair możesz użyć funkcji Substr() w połączeniu z Instr(), aby rozdzielić nazwisko na osobne pola. SUBSTR(CustomerName, INSTR(CustomerName, ', ')+2) = Alastair SUBSTR(CustomerName, 1, INSTR(CustomerName, ', ')-1) = MacIntyre W pierwszym wypadku Substr pobierze wszystkie znaki z ciągu, zaczynając od drugiego znaku po znaku „,” aż do końca ciągu. Pozostawienie trzeciego argumentu pustego spowoduje, że funkcja przyjmie go równego długości całego ciągu. W drugim przypadku funkcja zwróci wszystkie znaki od początku ciągu aż do znaku poprzedzającego przecinek. Decode Wielu programistów Accessa przyzwyczaiło się opierać na natychmiastowym porównaniu (IIf()) w swoich kwerendach. Oracle nie dostarcza podobnie nazywającej się funkcji, można za to użyć podobnie działającej funkcji Decode. Decode jest serią testów If/Then zakończonych przez Else. To oznacza, że jest to raczej konstrukcja typu Case Select niż IIf(). DECODE( value, if1, then1, if2, then2, ..., else) Ilość konstrukcji if/then jest prawie nieograniczona. Poniższe wyrażenie SQL jest prostym przykładem użycia funkcji Decode do zamiany nazw miast na regiony, w których leżą: Select loc, DECODE(loc, 'NEW YORK', 'MID-ATLANTIC', 'DALLAS', 'SOUTH', BOSTON', 'NEW ENGLAND', 'CHICAGO', 'MIDWEST', 'UNKNOWN') REGION FROM dept Wynik tej kwerendy przedstawia, w jaki sposób zostały pokazane regiony i w jaki sposób obsłużone zostało nieznane miasto przez część Else funkcji Decode. Select loc, DECODE(loc, 'NEW YORK', 'MID-ATLANTIC', 'DALLAS', 'SOUTH', BOSTON', 'NEW ENGLAND', 'CHICAGO', 'MIDWEST', 'UNKNOWN') As REGION FROM dept LOC REGION ---------- ------------ NEW YORK MID-ATLANTIC DALLAS SOUTH CHICAGO MIDWEST BOSTON NEW ENGLAND SUMMIT UNKNOWN Obliczenia w Oracle'u Dopóki dobry projekt struktury bazy nie będzie przechowywać większości wyników obliczeń, nie będziesz mógł tworzyć sensownych interfejsów lub raportów bez poznania funkcji matematycznych Oracle'a. Funkcje Oracle'a są bardzo podobne do tych, które występowały w VBA lub Accessie. Rozdział ten wskaże kilka różnic pomiędzy funkcjami Oracle'a i Accessa. Ceil() Ceil() nie ma odpowiednika w Accessie. Zwraca on najbliższą liczbę całkowitą większą lub równą wartości zadanej. CEIL(34.2) = 35 CEIL( -2.4) = -2 Floor() Floor() jest przeciwnością Ceil(), także nie mającą odpowiednika w Accessie. Funkcja zwraca najbliższą liczbę całkowitą mniejszą lub równą wartości zadanej jako argument. Floor(34.2) = 34 Floor( -2.4 ) = -3 Nvl() Funkcja Nvl() jest funkcją podstawiania wartości i jest podobna do funkcji NZ() w VBA. Umożliwia ona podstawienie zadanej wartości, gdy argument jest wartością null. Pomaga ona zapobiegać błędom matematycznym spowodowanym przez podstawienie wartości null do obliczeń. Posiada ona dwa parametry: ? Value – wymagana. Wartość lub odwołanie do wartości. ? Substitute – wymagana. Wartość zwracana przez funkcję, gdy Value będzie null. NVL(wartość, podstawienie) NVL(238, 15)=238 NVL(null, 15)=15 Round() W Accessie przez długi czas brakowało funkcji Round(). W Accessie 2000 użytkownicy nareszcie mogą z niej skorzystać. Funkcja ma dwa parametry: ? Value – wymagana. Wartość lub odwołanie do wartości do przetworzenia. ? Precision – nieobowiązkowa. Ilość miejsc po przecinku, do ilu będzie zaokrąglana liczba. Domyślnie przyjmowane jest zero. Sign() Sign() działa dokładnie tak jak funkcja Accessa Sgn(). Zwraca ona 1 dla liczb dodatnich i -1 dla ujemnych. Trunc() Zamiast zaokrąglać liczbę w górę lub w dół, Trunc() po prostu obcina liczbę do żądanej długości. Funkcja posiada dwa parametry: ? Value – wymagana. Wartość lub odwołanie do wartości do przetworzenia. ? Precision – nieobowiązkowa. Ilość miejsc po przecinku, do ilu będzie obcięta liczba. Domyślnie przyjmowane jest zero. Greatest/Least Greatest i Least używane są, aby wybrać pomiędzy dwiema lub więcej wartościami. Mogą być one użyte do liczb, ciągów lub dat. Gdy używane są do porównywania dat, jak w tym przykładzie poniżej, daty podawane w postaci tekstu muszą być konwertowane przez funkcję To_Date(), w przeciwnym wypadku zostaną potraktowane jako ciąg znaków i wynik funkcji nie będzie taki, jakiego się spodziewamy. W przykładzie użyta jest funkcja Least, aby wybrać wcześniejszą z dat, tę zapisaną w polu Hiredate lub 1 stycznia 1985. Funkcja Least wybierze wcześniejszą lub mniejszą wartość z podanych możliwości, podczas gdy Greatest wybierze największą. SELECT ENAME, LEAST(HIREDATE, TO_DATE('1-JAN-85')) FROM EMP ENAME LEAST(HIREDATE) ---------- -------------- JP 01-JAN-85 ALLEN 20-FEB-81 WARD 22-FEB-81 JONES 02-APR-81 MARTIN 28-SEP-81 BLAKE 01-MAY-81 CLARK 09-JUN-91 SCOTT 01-JAN-85 KING 17-NOV-81 TURNER 08-SEP-81 ADAMS 01-JAN-85 JAMES 03-DEC-81 FORD 03-DEC-81 MILLER 23-JAN-82 Obliczenia na datach Nie ma prawdopodobnie typu danych, który sprawia więcej kłopotu niż daty. Poniżej opiszemy kilka funkcji, które operują na datach. Arytmetyka Date jest typem danych zarówno w Oracle'u jak i w Accessie. Tak jak w Accessie daty zapisują więcej informacji niż to jest widoczne. W Oracle'u kolumna typu Date przechowuje rok, miesiąc, dzień, godzinę, minutę i sekundę. Oznacza to, że możesz przeprowadzać obliczenia na datach. Jednak w odróżnieniu od liczb, gdy dodasz liczbę do daty, otrzymujesz nową datę. Gdy odejmujesz jedną datę od drugiej, otrzymujesz liczbę oznaczającą czas pomiędzy tymi dwiema datami. W zależności od formatowania czas ten może wyglądać dowolnie, od lat po sekundy. Jest również możliwe, że liczba ta nie jest liczbą całkowitą – identycznie jak w Accessie. Sysdate Funkcja Sysdate() sięga do systemu operacyjnego i zwraca bieżącą datę i czas. Select SYSDATE FROM sys.Dual Wyrażenie to zwróci datę systemową, używając systemowej tabeli testowej. Add_Months Jeżeli pierwsza ocena pracownika powinna być po 6 miesiącach pracy, możesz użyć funkcji Add_Months, aby zaplanować ocenę. Add_Months posiada dwa parametry: ? Date – wymagana. Data lub odwołanie do prawidłowej daty. ? Count – wymagana. Ilość miesięcy, jaką należy dodać do Date. Poniższe wyrażenie SQL przedstawia datę pierwszej oceny pracownika. SELECT ename, hiredate, add_months(hiredate, 6) FROM emp SELECT ENAME, LEAST(HIREDATE, TO_DATE('1-JAN-85')) FROM EMP ENAME HIREDATE ADD_MONTH ---------- --------- --------- JP 27-JUL-97 27-JAN-98 ALLEN 20-FEB-81 20-AUG-81 WARD 22-FEB-81 22-AUG-81 JONES 02-APR-81 02-OCT-81 MARTIN 28-SEP-81 28-MAR-82 BLAKE 01-MAY-81 01-NOV-81 CLARK 09-JUN-81 09-DEC-81 SCOTT 19-APR-87 19-OCT-87 KING 17-NOV-81 17-MAY-82 TURNER 08-SEP-81 08-MAR-82 ADAMS 23-MAY-87 23-NOV-87 JAMES 03-DEC-81 03-JUN-82 FORD 03-DEC-81 03-JUN-82 MILLER 23-JAN-82 23-JUL-82 Często, gdy planujemy zdarzenia, potrzebujemy określonego czasu realizacji zdarzenia, aby zdążyć wykonać zakładane czynności. Można uzyskać datę rozpoczęcia realizacji poprzez wstawienie liczby ujemnej do drugiego argumentu funkcji Add_Months(). Months_Between Aby policzyć odstęp czasu pomiędzy dwiema datami, możesz odjąć jedną od drugiej. Miesiące jednak mają różną ilość dni i aby podać ilość miesięcy pomiędzy datami, musiałbyś wykonać sporo obliczeń. Funkcja Months_Between() zwraca różnicę w miesiącach pomiędzy datami, biorąc pod uwagę, które miesiące leżą pomiędzy nimi. Poniższe wyrażenie zamienia miesiące na lata poprzez podzielenie ich przez 12. Użyjemy również zaokrąglenia, aby otrzymać czytelny wynik. SELECT ename, hiredate, ROUND(MONTHS_BETWEEN(SYSDATE, hiredate)/12,2) "YEARS SERVICE" FROM emp ENAME HIREDATE YEARS SERVICE ---------- --------- ------------- JP 27-JUL-97 1.56 ALLEN 20-FEB-81 17.99 WARD 22-FEB-81 17.99 JONES 02-APR-81 17.88 MARTIN 28-SEP-81 17.39 BLAKE 01-MAY-81 17.8 CLARK 09-JUN-81 17.69 SCOTT 19-APR-87 11.83 KING 17-NOV-81 17.25 TURNER 08-SEP-81 17.44 ADAMS 23-MAY-87 11.74 JAMES 03-DEC-81 17.21 FORD 03-DEC-81 17.21 MILLER 23-JAN-82 17.07 Next_Day() Jeżeli jakieś zdarzenie ma miejsce danego dnia tygodnia przed lub po podanej dacie (jak większość kalendarzowych świąt, niektóre święta religijne i dni wypłaty), można policzyć daty, kiedy będzie ono wypadnie. Funkcja Next_Day() może pomóc w takich obliczeniach. Next_Day() posiada dwa parametry: ? Date – data lub odwołanie do prawidłowej daty ? Day – angielska nazwa dnia tygodnia ('Sunday', 'Monday', itd.) Poniższe wyrażenie przedstawia pierwsze dni wypłaty pracowników, zakładając, że dostają pieniądze w każdy piątek. SELECT ename, hiredate, next_day(hiredate, 'Friday') "PAYDAY!" FROM emp ENAME HIREDATE PAYDAY! ---------- --------- --------- JP 27-JUL-97 01-AUG-97 ALLEN 20-FEB-81 27-FEB-81 WARD 22-FEB-81 27-FEB-81 JONES 02-APR-81 03-APR-81 MARTIN 28-SEP-81 02-OCT-81 BLAKE 01-MAY-81 08-MAY-81 CLARK 09-JUN-81 12-JUN-81 SCOTT 19-APR-87 24-APR-87 KING 17-NOV-81 20-NOV-81 TURNER 08-SEP-81 11-SEP-81 ADAMS 23-MAY-87 29-MAY-87 JAMES 03-DEC-81 04-DEC-81 FORD 03-DEC-81 04-DEC-81 MILLER 23-JAN-82 29-JAN-82 To_Date() Funkcja To_Date() przeznaczona jest do zamiany daty zapisanej w postaci ciągu na wewnętrzny format daty rozpoznawany przez Oracle. Często będziesz jej używał w wyrażeniach Insert i Update. Bez niej nie byłbyś często w stanie przeprowadzić obliczeń na datach. To_Date posiada dwa parametry: ? String – wymagany. Ciąg reprezentujący datę (np.: 'July 27, 1997'). Domyślnym formatem daty jest „DD-MON-YYYY”. ? Format – nieobowiązkowy. SELECT TO_DATE('27-jul-97', 'dd-mon-yyyy') "Data sformatowana" FROM sys.dual Data sformatowana ----------- 27-JUL-1997 Problem roku 2000 Oracle nie przetwarza dat w sposób, w jaki robi to Access. Poniższe dwa wyrażenia SQL przedstawiają jak Oracle przypisuje daty do bieżącego stulecia (stulecia daty uzyskanej przez funkcję Sysdate()), gdy nie określimy sposobu konwersji. SELECT MONTHS_BETWEEN('27-JUL-2001', '27-JUL-1997') FROM SYS.DUAL MONTHS_BETWEEN('27-JUL-2001', '27-JUL-1997') -------------------------------------------- 48 SELECT MONTHS_BETWEEN('27-JUL-01', '27-JUL-97') FROM SYS.DUAL MONTHS_BETWEEN('27-JUL-01', '27-JUL-97') ---------------------------------------- -1152 Podczas tworzenia aplikacji musisz brać to pod uwagę. Pracując z datami, można użyć maski „RR”, aby konwertować zapisany dwucyfrowo rok na postać czterocyfrową według następujących zasad: jeżeli rok zawiera się w przedziale 0–49, zostanie przypisany do XXI wieku, natomiast pomiędzy 50 a 99 do wieku XX. SELECT TO_CHAR(TO_DATE('000727', 'RRMMDD'), 'DD-MON-YYYY') RRMMDD, TO_CHAR(TO_DATE('000727', 'YYMMDD'), 'DD-MON-YYYY') YYMMDD FROM SYS.DUAL RRMMDD YYMMDD ----------- ----------- 27-JUL-2000 27-JUL-1900 Poznajemy widoki i procedury przechowywane Przesyłanie wyrażeń SQL do wykonania przez Oracle jest świetnym sposobem na zwiększenie wydajności i zmniejszenie ruchu w sieci, lecz przechowywanie wyrażeń SQL w aplikacji nie jest najlepszym możliwym rozwiązaniem. Aby uruchomić całą siłę Oracle'a, skorzystać z pracy wykonanej w bazie danych, zmniejszyć koszty dodatkowych prac, zabezpieczyć swoją pracę i utrzymywać spójność danych, powinieneś użyć widoków i procedur przechowywanych. Widok w Oracle'u jest to po prostu zapytanie zapisane na serwerze. Tak jak kwerenda Select zapisana w Accessie, jest on skompilowany i posiada plan wykonania. Oznacza to, że będzie działać szybciej niż pytanie przesłane do wykonania przez SPT. Jest wiele zalet stosowania widoków. Można je wywoływać poprzez nazwę, która jest o wiele krótsza niż średnie wyrażenie SQL, przez co zmniejsza się obciążenie sieci. Ponieważ widok zapisany jest w bazie danych, posiada on dodatkowy poziom bezpie- czeństwa, co jest ważne w aplikacjach, które są słabo chronione. Ponieważ Twoja aplika- cja prawdopodobnie nie jest jedyną, która korzysta z bazy danych, możesz skorzystać z gotowych widoków, co oszczędza czas i zapewnia spójność danych w różnych aplikacjach. Widoki można tworzyć za pomocą Accessa lub korzystając z narzędzi Oracle'a. Aby utworzyć widok lub przeprowadzić inną zmianę struktury bazy danych, użytkownik, który pracuje musi mieć nadane prawo Resource. Sprawdź, czy posiadasz wystarczające uprawnienia, lub zapytaj o to administratora bazy danych. W tym rozdziale zajmujemy się dostępem do Oracle'a z Accessa, więc wszystko, co opiszę, można wykonać za pomocą Accessa. Jeżeli jednak chciałbyś użyć SQL Plus lub innego narzędzia Oracle'a, sprawdź w dokumentacji jak ich używać. Tworzenie widoków Widok jest po prostu wyrażeniem SQL, które zwraca rekordy. Ponieważ widok jest częścią struktury bazy danych, może być tworzony, zmieniany, używany lub usuwany za pomocą poleceń SQL. Spójrzmy na proste wyrażenie SQL zapisane zgodnie ze składnią Oracle'a. Select * from emp where sal>3000 Możesz utworzyć je w Accessie i uruchomić jako kwerendę przekazującą lub możesz utworzyć widok w Oracle'u i wywołać ten widok. Aby utworzyć widok z Accessa, utwórz kwerendę przekazującą, zawierającą wyrażenie definicji danych (DDL). Wyrażenie takie rozpoczyna się słowami kluczowymi Create, Alter, Drop itd. Aby utworzyć widok, powinieneś użyć następującej składni: Create [or Replace] View [Nazwa widoku] AS [wyrażenie SQL zwracające rekordy] Aby stworzyć widok z poprzedniego wyrażenia SQL, powinieneś użyć poniższego wyrażenia DDL uruchomionego przy użyciu SPT: Create or Replace View MyView As Select * from emp where sal>3000 Klauzula Or Replace powoduje, że nie zostanie wyświetlony błąd, gdy widok MyView już istnieje. Prawdopodobnie nie będziesz chciał zawsze dołączać klauzuli Or Replace, ponieważ bardzo łatwo wtedy omyłkowo zmienić definicję już istniejącego widoku. Wykonanie tej kwerendy utworzy widok, który zwraca wszystkie kolumny z tabeli emp, których wartość pola sal jest większa od 3000. Aby sprawdzić, czy widok został prawidłowo utworzony, możesz podłączyć ją do Accessa, jak gdyby była to zwykła tabela. Możesz również użyć go w dowolnym wyrażeniu SQL w kwerendzie przekazującej. Select * from MyView lub Select MyView.ename, Dept.deptno from MyView, Dept Where MyWiew.deptno=Dept.deptno Połączenie z Oracle'em poprzez ADO Tworzenie kwerend SPT jest świetną metodą komunikacji z Oracle'em, ponieważ przerzucają ciężar pracy na serwer zamiast na Jet, który nie jest uruchamiany. Możesz skorzystać z wszystkich zalet kwerend SPT, łącząc się z Oracle'em poprzez ADO. Podejście to pozwala efektywnie kontrolować poprawność danych, dynamicznie tworzyć wyrażenia SQL i wykonywać procedury przechowywane. Utworzenie połączenia z Oracle'em pociągało zwykle za sobą wiele skomplikowanych wywołań API z ODBC lub RDO, który jest podobnym do DAO interfejsem ODBC. Teraz mamy ADO i OLEDB, co zapewnia szybki, jednolity i elastyczny interfejs do różnych źródeł danych, włączając w to Oracle. Szczegółowy opis ADO i OLEDB znajduje się w rozdziale 6. „Wprowadzenie do obiektów danych ActiveX” i oraz w rozdziale 7. „Zaawansowane ADO”. W tej części rozdziału prześledzimy sposoby użycia ADO i OLEDB, aby połączyć się z bazą danych Oracle i wykonać wyrażenia SQL. Gdy używamy kwerend SPT, Oracle analizuje wyrażenia SQL i tworzy wynik. Oracle nie ma planu wykonania takiego zapytania, więc czas jego wykonania może nie być optymalny. Ponadto, gdy kilka aplikacji używa takiego samego zapytania lub procedury, musisz je zaprojektować i wstawić do wielu aplikacji. Lepszym podejściem jest utworzenie widoku lub procedury przechowywanej na serwerze. Może być on dzielony pomiędzy wiele aplikacji, zapewniając za każdym razem ten sam wynik. Ponieważ zarówno zapytanie tworzące widok, jak i procedura ma utworzony plan wykonania, więc będzie wykonana z maksymalną możliwą wydajnością. Omawialiśmy już, w jaki sposób utworzyć widok i procedurę przechowywaną przez użycie kwerend SPT. Wyrażenie SQL jest takie samo, ale użycie kodu ADO do zestawienia połączenia i utworzenia widoku lub procedury przechowywanej jest nieco inne. Przykłady w tym rozdziale są napisane w oparciu o dostawcę „Oracle Native OLEDB” z firmy Microsoft. Dostawca ten łączy z Oracle Call Interface (OCI), jednak w chwili obecnej nie wszystko, co da się zrobić za pomocą OCI, można wykonać, używając dostawcy OLEDB. Większość potrzebnych rzeczy da się wykonać, wykorzystując istniejący zestaw funkcji. Program z wydruku 17.1 tworzy widok w Oracle'u, a później otwiera go i wyświetla jego zawartość w oknie debuggera. Wydruk 17.1. Tworzenie widoku w Oracle'u z Accessa Function Create0racleView() As Boolean Dim conn As New ADODB.Connection Dim cmd As New ADODB.Command On Error GoTo Create0racleView Err With conn .Provider = "MSDAORA" .ConnectionString = "Data Source=empexample; User ID=Scott;password=Tiger" .Open End With cmd.ActiveConnection = conn cmd.CommandType = adCmdText ' Wyrażenie SQL Create or Replace oszczędza nam obsługi błędów cmd.CommandText = "Create or Replace View MyView As _ Select * firom emp where SAL>2000" cmd.Execute Create0racleView_Exit: conn.Close Set conn = Nothing Set cmd = Nothing Exit Function Create0racleView Err: ' Błąd Create0racleView = False ' Sprawdź, który błąd wystąpił przeszukując tablicę błędów With conn For i = 0 To .Errors.Count - 1 errDesc = errDesc & .Errors(i).Description & Chr(13) Next End With ' Powiadom użytkownika MsgBox "Wystąpił błąd: " & errDesc Resume Create0racleView Exit End Function Parametry W Accessie programista może tworzyć kwerendy sparametryzowane, mają one jednak tylko podstawowy plan wykonania i wykonują się w oparciu o ten plan z różnymi wartościami parametrów. Niestety Oracle nie udostępnia parametrów widoku poprzez dostawcę OLEDB. Alternatywą jest zmiana istniejącego widoku, tak jak pokazaliśmy powyżej. Można również użyć obiektu polecenia z OLEDB, aby utworzyć i dostarczyć parametry do wyrażenia SQL. Program na wydruku 17.2 przedstawia, w jaki sposób można to wykonać. Wydruk 17.2. Użycie parametrów Oracle'a z VBA Accessa Function OracleParams(SalAmnt As Long) As Boolean Dim conn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim rsfield as New Field Dim cmd As New ADODB.Command ' Tworzenie połączenia With conn .Provider = "MSDAORA" .ConnectionString = "Data Source=empexample; User ID=Scott;password=Tiger" .Open End With ' Użyjemy kursorów po stronie serwera With rs .CursorLocation = adUseServer End With ' Tworzenie obiektu polecenia With cmd cmd.ActiveConnection = conn ' Ustawienie CommandType, aby akceptował wyrażenia SQL cmd.CommandType = adCmdText ' Ustawienie tekstu polecenia cmd.CommandText = "Select * from emp where sal > ?" ' Tworzenie parametru i dołączenie go do zbioru ' parametrów polecenia cmd.Parameters.Append cmd.CreateParameter("SAL", adNumeric, adParamInput) ' Przypisanie wartości SalAmnt do pierwszego parametru cmd(0) = SalAmnt End With ' Wykonaj polecenie i przypisz wynik do obiektu ADO Recordset Set rs = cmd.Execute If conn.Errors.Count = 0 Then OraclParams = True End If rs.MoveFirst While Not rs.EOF strfield = "" For Each rsfield In rs.Fields strfield = strfield & " " & rsfield Next Debug.Print strfield & Chr(9) rs.MoveNext Wend End Function Tworzenie procedur przechowywanych Procedura przechowywana w Oracle'u jest podobna do modułu w Accessie. Wykonuje zbiór poleceń na serwerze. Głównymi zaletami procedur przechowywanych są ich szybkość, niezawodność i bezpieczeństwo. Mogą one być użyte do wymuszania reguł biznesowych, kontroli poprawności i zapewnienia transakcyjności. Najważniejszą wadą procedur jest sposób ich tworzenia i uruchamiania. Oracle nie dostarcza środowiska programowania podobnego do środowiska Accessa, przez to tworzenie i edycja procedur przechowywanych jest trudna. Oracle 8 dostarcza program zarządzania strukturą bazy, który umożliwia tworzenie i kontrolę poprawności procedur, jednak wciąż nie jest to idealne rozwiązanie. Dodatkowo z racji tego, że procedury są zależne od serwera bazy danych, gdy zmieniasz serwer, musisz również zmienić procedury przechowywane. Architektura wielowarstwowa została tak zaprojektowana, aby ograniczyć tę niedogodność. Nie ma żadnego powodu, aby umieszczać całą skomplikowaną logikę aplikacji na serwerze (tak samo jak nie ma powodu, aby umieszczać ją na kliencie), dzięki temu procedury przechowywane są dużo prostsze od innych obiektów zapewniających logikę biznesową i inne operacje. Poniżej utworzymy i uruchomimy prostą procedurę przechowywaną. Aby tworzyć procedury w swojej przestrzeni tabel bazy danych, trzeba posiadać prawo systemowe Create Procedure, które jest częścią roli Resource. Aby utworzyć procedurę w innej przestrzeni tabel, musisz posiadać prawo Create Any Procedure. Porozmawiaj z administratorem bazy, jeżeli nie jesteś pewien, jakie posiadasz uprawnienia. Procedura dzieli się na następujące części: ? Deklaracja parametrów. ? Rozpoczęcie przetwarzania. ? Zatwierdzenie zmian. ? Obsługa wyjątków. ? Odwołanie zmian. ? Obsługa błędów. Procedura wstawiająca rekord do tabeli z dwoma polami przedstawiona jest na wydruku 17.3. Wydruk 17.3. Procedura Oracle'a dodająca nowy rekord (Ename CHAR, EJob CHAR) IS BEGIN INSERT INTO SCOTT.TESTTABLE VALUES(Ename, EJob); COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; END; W tym przypadku procedura posiada dwa parametry, nazwisko i nazwę stanowiska. Access może utworzyć procedurę poprzez kwerendę SPT w następujący sposób: CREATE OR REPLACE PROCEDURE MyStoredProcedure (Ename CHAR, EJob CHAR) IS BEGIN INSERT INTO SCOTT.TESTTABLE VALUES(Ename, EJob); COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; END; Po utworzeniu procedury może być ona wywoływana poprzez kwerendę SPT lub VBA. Uruchamianie procedury Wywołanie procedury z kwerendy SPT jest nieco inne niż wywołanie widoku: {call MyStoredProcedure } Nawiasy klamrowe udają składnię, jakiej spodziewa się Oracle, używając Oracle call interface, używanego przez dostawcę OLEDB. Wykonywanie procedury z VBA poprzez dostawcę OLEDB dla Oracle'a wygląda nieco inaczej. Funkcja przedstawiona na wydruku 17.4 korzysta z tego, że procedury ujawniają swoje parametry w sposób, który może być użyty w VBA. Podając nazwę procedury przechowywanej, nazwę tabeli, do której chcesz wstawić rekord i wypełniając wymagane argumenty w tablicy paramArray uruchamianej funkcji, możesz uruchomić większość procedur przechowywanych za pomocą funkcji przedstawionej na wydruku 17.4. Wydruk 17.4. Wykonanie procedury przechowywanej z parametrami za pomocą VBA w Accessie Function RunOracleStoredProcedures(ProcName As String, _ DestTable as String, ParamArray ParamArgs() As Variant) As Boolean Dim conn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim i As Integer Dim cmd As New ADODB.Command Dim rsfield As Field Dim strfield As String With conn .Provider = "MSDAORA" .ConnectionString = "Data Source=empexample;_ User ID=Scott;password=Tiger" .Open End With cmd.ActiveConnection = Conn cmd.CommandType = adCmdStoredProc cmd.CommandText = ProcName For i = 0 To UBound(ParamArgs()) With cmd.Parameters(i) .Type = adChar .Direction = adParamInput .Value = ParamArgs(i) End With Next cmd.Execute ' A teraz wyświetlamy wynik w oknie uruchamiania ' Nie będziesz potrzebował tego fragmentu kodu ' w swoich aplikacjach rs.Open "Select * from " & destTable, conn,_ adOpenForwardOnly, adLockReadOnly rs.MoveFirst While Not rs.EOF strfield = "" For Each rsfield In rs.Fields strfield = strfield & " " & rsfield Next Debug.Print strfield & Chr(9) rs.MoveNext Wend Set rs = Nothing conn.Close RunOracleStoredProcedures = True End Function Wykonywanie wielu prostych procedur przechowywanych umożliwia tworzenie złożonej logiki w znanym środowisku VBA, korzystając z jego zaawansowanych możliwości uruchamiania kodu i obsługi błędów. Tworzenie niezwiązanego interfejsu do Oracle'a Mając na uwadze ograniczenia wydajności i duże obciążenie sieci, gdy używamy tabel połączonych, powinniśmy rozważyć użycie niezwiązanego interfejsu użytkownika wszędzie tam, gdzie jest to możliwe. Utworzenie niezwiązanego interfejsu pomaga zastosować w Twojej aplikacji architekturę wielowarstwową, co zwiększa jej skalowalność i ułatwia jej konserwację. Umożliwi także łatwe łączenie różnych narzędzi programowania. Możesz użyć ADO, ADOX, DAO, RDO i inne narzędzia tam, gdzie uważasz, że przyniosą korzyści. Niezwiązany interfejs ułatwia migrację do innego środowiska, jak na przykład Visual Basic. Przez to, że jesteś pewny, że przetwarzanie odbywa się na serwerze, możesz również uzyskać lepszą wydajność. W przedstawionym tu ćwiczeniu utworzymy prosty niezwiązany interfejs dla Oracle'a, który wygląda i zachowuje się identycznie jak formularz związany. Aby pokazać elastyczność ADO, użyjemy wyrażeń SQL oraz metod obiektu Recordset. Formularz będzie wyświetlał rekordy tabeli EMP. Użytkownik będzie mógł wstawiać i usuwać rekordy z bazy danych Oracle. Można będzie zmieniać rekordy w tabeli bez konieczności każdorazowego zapisywania zmienionego rekordu. Tworzenie niezwiązanego interfejsu Na początek utwórz formularz taki, jak na rysunku 17.3. Rysunek 17.3. Formularz z danymi w trybie projektowania Dla uproszczenia, nazwy obiektów ekranowych odpowiadają nazwom pól w tabeli EMP: ? Empno, ? Ename, ? Job, ? Mgr, ? Hiredate, ? Sal, ? Comm, ? Deptno. Przyciski nawigacyjne i manipulacyjne będą nazywały się następująco: ? BtnGotoFirst, ? BtnGotoPrevious, ? BtnGotoNext, ? BtnGotoLast, ? BtnEdit, ? BtnNew, ? BtnDelete, ? BtnSave, ? BtnClose. Tworzenie zmiennych globalnych Podstawowe operacje można zrobić na kilka sposobów. Dla uproszczenia przyjmijmy, że obiekty Connection i Recordset oraz zmienna, która informuje o zmianie danych, będą przechowywane przez trzy zmienne globalne przechowywane w głównym module: Global conn As ADODB.Connection Global rs As ADODB.Recordset Global EditRec As Boolean Ładowanie danych i inicjalizacja formularza Program przedstawiony na wydruku 17.5 wykonany zostanie jako obsługa komunikatu OnOpen. Procedura ta załaduje dane i zainicjuje aplikację. Wydruk 17.5. Utworzenie i otwarcie połączenia z Oracle'em oraz wypełnienie formularza Private Sub Form Open(Cancel As Integer) Set conn = New ADODB.Connection Set rs = New ADODB.Recordset With conn .Provider = "MSDAORA" .ConnectionString = "Data Svurce-ernpexample;_ User ID=Scott;password=Tiger" .Open End With rs.CursorLocation = adUseClient rs.Open "Select * from emp", conn, adOpenStatic,_ adLockOptimistic, adAsyncFetch FillForm EditRec = True End Sub Oracle nie zwraca obiektów typu Recordset, ale dostawca OLEDB przechwytuje wynik wyrażenia SQL i zwraca go do programu jako Recordset. Dostawca OLEDB przykrywa wywołania Oracle Call Interface tak, że dla aplikacji nie ma różnicy pomiędzy Oracle'em a innymi źródłami danych. Używając globalnej zmiennej Recordset, można szybko i łatwo wypełnić formularz danymi pochodzącymi z pierwszego rekordu. Następnie procedura ustawia zmienną EditRec na true, co wskazuje, że dane na formularzu są gotowe do edycji. Zdarzenie OnOpen wywołuje funkcję FillForm, która zamieszczona jest na wydruku 17.6. Wydruk 17.6. Wypełnianie formularza danymi Function FillForm() As Boolean On Error GoTo FillForm Err [Empno] = rs(0) [ENAME] = rs(1) [Job] = rs(2) [MGR] = rs(3) [HIREDATE] = rs(4) [SAL] = rs(5) [COMM] = rs(6) [DEPTNO] = rs(7) FillForm = True FillForm_Exit: Exit Function FillForm_Err: FillForm = False Exit Function End Function Programowanie przycisków sterujących Aby przeglądać cały wynik zapytania, należy oprogramować przyciski sterujące, tak jak jest to pokazane na wydrukach od 17.7 do 17.10. Wydruk 17.7. Przejście do pierwszego rekordu Private Sub btnGotoFirst_Click() On Error Resume Next rs.MoveFirst If Not rs.BOF Then FillForm End If CurrentContext Me End Sub Wydruk 17.8. Przejście do poprzedniego rekordu Private Sub btnGotoPrevious_Click() On Error Resume Next rs.MovePrevious If Not rs.BOF Then FillForm End If CurrentContext Me End Sub Wydruk 17.9. Przejście do następnego rekordu Private Sub btnGotoNext_Click() On Error Resume Next rs.MoveNext If Not rs.BOF Then FillForm End If CurrentContext Me End Sub Wydruk 17.10. Przejście do ostatniego rekordu Private Sub btnGotoLast_Click() On Error Resume Next rs.MoveLast If Not rs.BOF Then FillForm End If On Error GoTo 0 CurrentContext Me End Sub Bieżący stan przycisków nawigacyjnych zależy od pozycji w zestawie rekordów wyniku. Funkcja CurrentContext, która pobiera jako argument obiekt formularza, włącza oraz wyłącza przyciski nawigacyjne (wydruk 17.11). Wydruk 17.11. Włączanie i wyłączanie przycisków nawigacyjnych Sub CurrentContext(frm As Form) Dim bFirstRec As Boolean Dim bLastRec As Boolean bFirstRec = (rs.AbsolutePosition = 1) bLastRec = (rs.AbsolutePosition = rs.RecordCount) With frm If Not bFirstRec And Not bLastRec Then !btnGotoFirst.Enabled = True !btnGotoPrevious.Enabled = True !btnGotoLast.Enabled = True !btnGotoNext.Enabled = True GoTo CurrentContext_Exit End If If bFirstRec And bLastRec Then !btnEdit.SetFocus !btnGotoFirst.Enabled = False !btnGotoPrevious.Enabled = False !btnGotoLast.Enabled = False !btnGotoNext.Enabled = False GoTo CurrentContext_Exit End If If bFirstRec Then !btnGotoLast.Enabled = bFirstRec !btnGotoNext.Enabled = bFirstRec !btnGotoLast.SetFocus !btnGotoFirst.Enabled = Not bFirstRec !btnGotoPrevious.Enabled = Not bFirstRec GoTo CurrentContext_Exit End If If bLastRec Then !btnGotoFirst.Enabled = bLastRec !btnGotoPrevious.Enabled = bLastRec !btnGotoFirst.SetFocus !btnGotoLast.Enabled = Not bLastRec !btnGotoNext.Enabled = Not bLastRec GoTo CurrentContext_Exit End If End With End Sub Zmiana danych Oracle'a przy użyciu formularza Do tej pory możesz tylko oglądać dane, ale zmiany, jakie wprowadziłeś, nie zostaną zapisane w bazie. Funkcja z wydruku 17.12 wywołuje metodę Update obiektu OLEDB Recordset, aby wysłać zmiany do Oracle'a zaraz po tym, jak zmieniłeś dane. Daje to możliwości takie same jak możliwości formularza związanego. Funkcja pokazana na wydruku 17.12 musi być wywołana jako odpowiedź na zdarzenie AfterUpdate dla każdego pola tekstowego. Wydruk 17.12. Funkcja UpdateField Function UpdateField(FieldName As Variant, NewValue As Variant)_ As Boolean If EditRec = False Or IsEmpty(EditRec) Then Exit Function Dim rsOrigSource As String Dim errDesc As String Dim i As Integer On Error GoTo UpdateField Err ' Zachowaj początkowe źródło recordset-u na wypadek błędu rsOrigSource = rs.Source ' Próba zmiany pola przy użyciu metody update obiektu Recordset rs.Update FieldName, NewValue ' Udało się UpdateField = True UpdateField_Exit: Exit Function UpdateField_Err: ' Błąd UpdateField = False ' Sprawdź, jaki wystąpił błąd, przeszukując tablicę błędów With conn For i = 0 To .Errors.Count - 1 errDesc = errDesc & .Errors(i).Description & Chr(13) Next End With ' Informacja dla użytkownika MsgBox "Wystąpił błąd: " & errDesc ' Musisz odwołać metodę Update metodą CancelUpdate ' gdyż nie będziesz mógł wykonać żadnej operacji na wyniku rs.CancelUpdate ' Zamknięcie istniejącego wyniku rs.Close ' Otwórz Recordset z zachowanym źródłem, przywracając ' mu stan początkowy rs.Open rsOrigSource, conn, adOpenStatic, adLockOptimistic, _ adAsyncFetch ' Wywołaj FillForm Forms![forml].FillForm Resume UpdateField_Exit End Function Funkcja UpdateField może być wywoływana przez każde zdarzenie AfterUpdate, gdy zaznaczymy wszystkie pola tekstowe na formatce i wstawimy wyrażenie pokazane na wydruku 17.13. Alternatywą do zapisywania zmian natychmiast może być buforowanie zmian i zapisywanie ich po przejściu do innego rekordu. Możesz także użyć wywołania przez ADO procedury przechowywanej i przekazać do niej nowe wartości. Wydruk 17.13. Wyrażenie zapisujące zmiany po edycji zawartości pola =UpdateField(screen.activecontrol.[Name],screen.activecontrol) Teraz, gdy przechodzisz między rekordami i zmieniasz dane pracowników, zmiany zapisane będą w bazie po przejściu do innego rekordu. Wstawienie danych do Oracle'a przy użyciu formularza Aby dodać nowy rekord, powinieneś wyczyścić wszystkie pola na formularzu i ustawić zmienną EditRec na false. Kod programu z wydruku 17.14 powinien być wprowadzony jako obsługa zdarzenia OnClick przycisku btnNew. Wydruk 17.14. Przygotowanie formularza do wpisania nowego rekordu Private Sub btnNew Click() ClearForm EditRec = False End Sub Należy jeszcze napisać procedurę czyszczącą formularz. Dla naszych celów, może ona być zapisana w standardowym module poza formularzem. Funkcja ta jest niezwykle prosta (wydruk 17.15). Wydruk 17.15. Czyszczenie formularza Sub ClearForm() Me![Empno] = "" Me![ENAME] = "" Me![Job] = "" Me!(MGR] = "" Me![HIREDATE] = "" Me![SAL] = "" Me![COMM] = "" Me![DEPTNO] = "" End Sub Zapisywanie danych do Oracle'a przy użyciu formularza Gdy trzeba zapisać rekord, możesz wywołać poniższą procedurę za pomocą zdarzenia OnClick przycisku btnSave. Sprawdzając stan zmiennej EditRec, wiemy, czy wprowadzasz nowy rekord i tworzymy odpowiednie wyrażenie SQL. Zostanie ono wykonane poprzez obiekt Command. Technika ta pokazana jest na wydruku 17.16, jest standardowa dla Oracle'a. Wydruk 17.16. Zapis do Oracle'a poprzez SQL i ADO Private Sub btnSave Click() Dim cmd As New ADODB.Command Dim strCmdtxt as string ' Jeżeli wstawiamy nowy rekord If EditRec = False Then ' Po upewnieniu się, że obiekt Command jest prawidłowo ustawiony ' utworzymy i wykonamy wyrażenie SQL Insert With cmd .ActiveConnection = conn .CommandType = adOmdText with Me strOmdtxt = strOmdtxt & "insert into emp values (" strCmdtxt = strCmdtxt & "'![Empno] '," strOmdtxt = strCmdtxt & "'![ENAME] '," strCmdtxt = strCmdtxt & "'![Job] '," strCmdtxt = strCmdtxt & "'![MGR] '," strCmdtxt = strCmdtxt & "' to date('" &![HIREDATE] & "','MM/DD/YY') '," strCmdtxt = strCmdtxt & "'![SAL] '," strCmdtxt = strCmdtxt & "'![COMM] '," end with .Execute End With End If ' Zamknij, ustaw i otwórz jeszcze raz Recordset With rs .Close .CursorLocation = adUseClient .Open "Select * from emp", conn, adOpenStatic, adLockOptimistic, adAsyncFetch End With ' Wypełnij formularz FillForm ' Zmień tryb aplikacji na edycję danych EditRec = True End Sub Usuwanie danych przy użyciu formularza To samo podejście zastosowane jest przy usuwaniu danych. Procedura na wydruku 17.17 usuwa bieżący rekord z Oracle'a, gdy wykonamy ją jako obsługę zdarzenia OnClick przycisku btnDelete. Wydruk 17.17. Usunięcie bieżącego rekordu Private Sub btnDelete Click() Dim cmd As New ADODB.Command ' Jeżeli zmieniamy rekord If EditRec = True Then ' Po upewnieniu się, że obiekt command jest prawidłowo ustawiony ' utworzymy i wykonamy wyrażenie SQL Delete With cmd .ActiveConnection = conn .CommandType = adCmdText .CommandText = "Delete from emp where empno= " & Me![Empno] .Execute End With End If ' Zamknij, ustaw i otwórz jeszcze raz Recordset With rs .Close .CursorLocation = adUseClient .Open "Select * from emp", conn, adOpenStatic, adLockOptimistic, adAsyncFetch End With ' Wypełnij formularz FillForm End Sub Aby przyciski nawigacyjne odzwierciedlały zawartość formularza w czasie przeglądania dostępnych rekordów, przypisz kod zamieszczony na wydruku 17.18 do zdarzenia OnCurrent formularza. Wydruk 17.18. Wypełnienie pól formularza danymi i sprawdzenie bieżącego kontekstu Private Sub Form Current() On Error Resume Next Dim bFirstRec As Boolean Dim bLastRec As Boolean If Not rs.BOF Then With Me ![Empno] = rs(0) ![ENAME] = rs(1) ![Job] = rs(2) ![MGR] = rs(3) ![HIREDATE] = rs(4) ![SAL] = rs(5) ![COMM] = rs(6) ![DEPTNO] = rs(7) End With End If Current0ontext Me End Sub Zamykanie połączenia z Oracle'em Gdy zamykamy formularz, należy zakończyć połączenie z Oracle'em i ustawić obiekty Connection i Recordset na wartość nothing, ponieważ może zechcesz użyć tych obiektów w innych aplikacjach. Funkcja przedstawiona na wydruku 17.19 pomoże przeprowadzić prace porządkowe. Wydruk 17.19. Porządki podczas zamykania formatki Private Sub btnClose_Click() On Error GoTo Err_btnClose_Click_Err DoCmd.Close Exit_btnClose_Click_Exit: conn.Close Set conn = Nothing Set rs = Nothing Exit Sub Err_btnClose_Click_Err: MsgBox err.Description Resume Exit_btnClose_Click_Exit End Sub Poprzez wprowadzanie innych obiektów Recordset, trwałych obiektów Recordset oraz przez użycie uproszczeń dostawcy OLEDB dla Oracle Call Interface możesz utworzyć cały niezwiązany interfejs użytkownika do Oracle'a, korzystając z szybkości działania, skalowalności i odporności Oracle'a w Twojej aplikacji Accessa. Część VI Współoperatywność W tej części: ? Użycie automatyzacji ActiveX. ? Integracja z Office 2000. ? Użycie Visual Basic z Accessem. Rozdział 18. Użycie automatyzacji ActiveX W tym rozdziale: ? Co to jest automatyzacja ActiveX. ? Dlaczego używamy automatyzacji. ? Odróżnienie serwera automatyzacji od klienta automatyzacji. ? Określanie zasobów wymaganych przez automatyzację. ? Wielka trójka. ? Tworzenie i ustanowienie odwołania do innej aplikacji. ? Przypisywanie zmiennej obiektowej do aplikacji. ? Tworzenie egzemplarza aplikacji. ? Użycie metod i właściwości obiektów automatyzacji. ? Zwalnianie obiektu automatyzacji. ? Łączymy wszystko razem. ? Zamykanie aplikacji serwera automatyzacji. W obecnych czasach, częściej niż do tej pory, żąda się od programistów szybkiego tworzenia skomplikowanych aplikacji, które są zintegrowane z innymi programami. Szczęśliwie, używając automatyzacji ActiveX (dawniej zwanej OLE Automation), aplikacje mogą współpracować ze sobą, tworząc kompletne rozwiązania informatyczne. Może to poważnie skrócić czas tworzenia programów, ponieważ zamiast tworzenia jakiejś funkcji programista może połączyć się z innym programem i użyć jego opcji. W tym rozdziale opiszę zasady i techniki użycia automatyzacji ActiveX. W rozdziale 19. „Integracja z Office 2000” opiszę, jak użyć automatyzacji ActiveX w celu zintegrowania Accessa 2000 z resztą pakietu Office. Co to jest automatyzacja ActiveX Technologia ActiveX jest bazowana na Component Object Model (COM) firmy Microsoft. Automatyzacja ActiveX pozwala na współpracę programów ze sobą. Automatyzacja pozwala jednemu programowi na dostęp i manipulowanie obiektami innego programu. Przykładem użycia automatyzacji jest drukowanie listów i raportów w Wordzie z Accessa. Dlaczego używamy automatyzacji Użycie automatyzacji jest efektywną metodą tworzenia i rozbudowy aplikacji. Automatyzacja może radykalnie skrócić czas tworzenia aplikacji, ponieważ zamiast tworzyć i testować opcję od podstaw, możemy ją sobie „pożyczyć” z innej aplikacji. Nie ma powodów, abyś tworzył swój edytor tekstów lub arkusz kalkulacyjny do użycia w Accessie. Dużo prościej użyć automatyzacji i niektórych technik opisanych w tym rozdziale, aby użyć w Twojej aplikacji Worda czy Excela. Umożliwia to skupienie się na opcjach niedostarczonych przez inne programy, co będzie bardzo korzystne dla użytkowników. Różnice między serwerem automatyzacji a klientem automatyzacji Gdy dwie aplikacje współpracują ze sobą, ważne jest, aby ustalić, która z nich udostępnia swoje obiekty, a która ich używa. Serwer automatyzacji jest aplikacją, która udostępnia obiekty klasy Automation. Klient automatyzacji (nazywany czasami kontrolerem automatyzacji) to aplikacja, która decyduje, które obiekty będą używane i w jaki sposób. Na przykład, jeżeli przycisk w Accessie uruchamia drukowanie listu w Wordzie, serwerem automatyzacji jest Word, natomiast klientem jest Access. Określanie zasobów wymaganych przez automatyzację Ponieważ jedna aplikacja za pomocą automatyzacji kontroluje inną, zostaną otwarte co najmniej dwa programy. Zawsze, gdy uruchamiamy kolejną aplikację, potrzebna jest dodatkowa ilość pamięci oraz mocy procesora. Jakie zasoby sprzętowe są wymagane, aby sterować Wordem z Accessa, jest bardzo subiektywną decyzją. Minimalną akceptowalną wydajność zapewnia procesor Pentium II z 24 MB pamięci RAM. Oczywiście szybszy procesor może istotnie poprawić wydajność, jednak duża ilość pamięci RAM jest bardziej pożyteczna niż moc procesora. Jeżeli wydajność programów używających automatyzacji jest niewystarczająca, najpierw dodaj pamięć, a dopiero później wymieniaj procesor na lepszy. Wielka trójka Mamy trzy etapy użycia automatyzacji: 91. Pobranie obiektu Automation. Utworzenie nowego albo odwołanie się do już istniejącego. 92. Użycie obiektu Automation w aplikacji. 93. Zwolnienie obiektu Automation. Przykładowo, jeżeli chciałbyś wydrukować list lub raport w Wordzie z Accessa, pierwszym krokiem powinno być utworzenie lub pobranie odwołania do aplikacji Word. Następnie używamy obiektów, właściwości i metod Worda (takich jak otwarcie, edycja lub wydruk dokumentu). Po zakończeniu pracy należy zwolnić aplikację Word. Tworzenie i ustanowienie odwołania do innej aplikacji Aby użyć jakiejś aplikacji, niezbędne jest ustanowienie odwołania do tej aplikacji, poprzez utworzenie zmiennej obiektowej i przypisanie jej egzemplarza aplikacji. Ustanawianie odwołania do innej aplikacji Za pomocą automatyzacji używasz i sterujesz pracą innych aplikacji spoza Accessa. Ilekroć używa się komponentu lub aplikacji spoza Accessa, musisz ustanowić odwołanie do tej aplikacji. Aby to zrobić, otwórz edytor Visual Basica i wybierz Tools, References. Na ekranie pojawi się okno dialogowe References, które zawiera listę bibliotek typów, programów, bibliotek DLL i kontrolek ActiveX (rysunek 18.1). Ustaw odwołanie do aplikacji, której chcesz użyć w swoim programie. Na przykład, aby odwołać się do Worda 2000, zaznacz pole wyboru obok Microsoft Word 9.0 Object Library. Jeżeli nie możesz znaleźć potrzebnej Ci biblioteki na liście, naciśnij przycisk Browse i odszukaj ją na dysku. Po ustanowieniu odwołania do aplikacji możesz przeglądać jej obiekty, właściwości i metody, oraz używać ich. Rysunek 18.1. Okno dialogowe odwołań Przegląd obiektów, właściwości i metod Przed omówieniem sposobów użycia obiektów innej aplikacji przypomnijmy kilka podstawowych pojęć. Bardzo ważne jest, abyś rozumiał pojęcia: obiekt, właściwość i metoda. Bez tego nie ma sensu czytanie reszty tego rozdziału. Obiekt jest elementem, który może być lub będzie użyty do programowania. W Accessie obiektami są formularze, pola tekstowe, przyciski i tego typu elementy. Używając automatyzacji, inne aplikacje i ich obiekty mogą być programowane za pomocą Accessa. Microsoft Office zawiera ponad 500 obiektów, które możesz używać w swoich aplikacjach. Przykładowo Word udostępnia obiekt Document, a Excel obiekt Worksheet. Właściwość jest charakterystyką obiektu. Właściwość może być rozumiana jako przymiotnik opisujący obiekt. W Accessie, właściwościami pola tekstowego są: nazwa, widoczność, kolor i inne tego typu cechy. Analogicznie, gdy używamy obiektów z innych aplikacji, mają one właściwości, które mogą być zmieniane poprzez automatyzację. Na przykład, podobnie do formularzy Accessa, aplikacje Word i Excel mogą być ukrywane i pokazywane poprzez ustawienie odpowiedniej właściwości. Większość właściwości może być zarówno odczytywana jak i zapisywana. Metoda to działanie na obiekcie. Może być rozumiana jako czasownik w zdaniu. Przykładem metody Accessa jest Close, natomiast przykładem metody Excela jest Quit, która zamyka Excela. Poznajemy strukturę obiektów Gdy korzystamy z innej aplikacji, dobrze jest najpierw zapoznać się ze strukturą obiektów tej aplikacji. Łatwo wtedy sprawdzić, z których obiektów można skorzystać, aby wykonać określoną czynność. Model obiektów stanowi szablonową reprezentację struktury aplikacji. Jest to szybka i prosta metoda sprawdzenia, jakie obiekty są dostępne w programie. Modele różnych aplikacji można znaleźć w ich plikach pomocy. W rozdziale 19. przedstawię modele obiektów programów Microsoft Office. Użycie narzędzia Object Browser Inną metodą szybkiego odszukania obiektów dostępnych w aplikacji jest użycie narzędzia Object Browser. Zaletami tego sposobu jest dostęp do właściwości, metod i zdarzeń oraz to, że obiekty te są połączone z ich plikami pomocy. Object Browser jest świetnym narzędziem do tego, aby szybko odszukać właściwy obiekt i poznać jego sposób działania. Aby użyć Object Browser wybierz Object Browser z menu View w edytorze Visual Basica. Możesz również nacisnąć F2. Object Browser pokazany jest na rysunku 18.2. Rysunek 18.2. Object Browser pokazujący obiekty Worda Przy pierwszym otwarciu przeglądarki pole listy rozwijanej w lewym górnym rogu będzie ustawione na All Libraries. To ustawienie powoduje, że są widoczne wszystkie obiekty aplikacji, do których ustawiliśmy odwołanie. Pierwszym krokiem powinno być wybranie właściwej aplikacji na liście rozwijanej tak, aby widoczne były tylko jej obiekty. Przykładowo, gdy wybierzemy Word, wyświetlone zostaną tylko obiekty Worda. Druga lista służy do szukania. Przykładowo, jeżeli chcemy odnaleźć okno komunikatu, ustawiamy górną listę wyboru na All Libraries, poniżej wpisujemy MsgBox i naciskamy na ikonę z lornetką (rysunek 18.3). Lewy dolny panel zatytułowany jest Classes. W panelu tym wyświetlane są dostępne typy obiektów w wybranej bibliotece. Gdy z listy zostanie wybrana klasa, na liście Member of zostaną wyświetlone właściwości, metody i zdarzenia. Prawy dolny panel zatytułowany Members, przedstawia zawartość klasy wybranej po lewej stronie. Na przykład, jeżeli wybrany zostanie obiekt Application, prawy panel będzie pokazywał wszystkie właściwości, metody, zdarzenia i stałe, które zawiera obiekt zaznaczony na liście klas. Rysunek 18.3. Szukanie MsgBox w Obiect Browser Skąd Object Browser czerpie informacje o obiektach, właściwościach i metodach? Z większością aplikacji dostarczany jest plik biblioteki typów, w którym zapisane są informacje o obiektach aplikacji, właściwościach, metodach i stałych. Object Browser wyświetla informację z biblioteki typów. Biblioteki te zapisywane są zwykle w plikach z rozszerzeniem .TLB lub .OLB. Domyślnie elementy wyświetlane w panelach Classes i Members są uporządkowane alfabetycznie. Dobrze jest nacisnąć prawy klawisz myszki na panelach i wybrać Group Members. Spowoduje to pogrupowanie listy według typów elementów. Elementy w każdej grupie uporządkowane będą alfabetycznie. Na samym dole okna wyświetlana jest składnia użycia wybranego elementu. Na przykład, po wybraniu obiektu Application z Accessa i zaznaczeniu metody DLookup, w oknie na dole Object Browsera wyświetlona zostanie właściwa składnia. Po dalsze informacje o wybranym elemencie można uzyskać, naciskając F1 i przeglądając pomoc podręczną. Tworzenie zmiennej obiektowej Zmienna jest fragmentem pamięci przeznaczonym do zapisywania i odczytywania informacji. Niewątpliwie masz już duże doświadczenie w stosowaniu prostych zmiennych, takich jak liczby lub ciągi znaków. Poniższy przykład przedstawia sposób deklaracji i użycia dwóch prostych zmiennych: Dim strName as String Dim I as integer StrName = "Bob" I = 10 W przykładzie tym zmienne zawierają zadeklarowany typ danych i dane tych typów mogą być przypisywane do zmiennej i z niej odczytywane. Zmienne obiektowe deklaruje się instrukcją Dim, identycznie jak zmienne proste. Dim objWord.application Dim objExcel.application Zawsze kwalifikuj wszystkie obiekty użyte w automatyzacji. Zamiast Dim objWord as Application używaj Dim objWord as Word.Application Kilka programów, do których się odwołujesz, może posiadać obiekt Application. Kwalifikacja nazwy obiektu zapewnia użycie właściwego obiektu i prawidłowe działanie programu Odwołanie do pracującej aplikacji Po utworzeniu zmiennej obiektowej następnym krokiem jest odwołanie się do aplikacji, której chcesz użyć. Jednak pamiętaj, nie wiesz czy aplikacja ta jest uruchomiona czy nie. Jeżeli chcesz użyć Worda, użytkownik być może ma go już otwartego. W tym wypadku, możesz użyć do Twoich celów bieżącego egzemplarza Worda. W przeciwnym wypadku, gdy otworzysz kolejny egzemplarz Worda, błyskawicznie zużyjesz zasoby w komputerze. Aby sprawdzić, czy jest uruchomiony program, użyj funkcji GetObject. Funkcja ta zwróci odwołanie do aktualnie uruchomionej aplikacji. ' Deklaracja zmiennej obiektowej objWord Dim objWord as Word.Application ' Użycie funkcji GetObject do pobrania odwołania do ' aktualnie uruchomionej aplikacji Set objWord = GetObject(, "Word.Application") Przypisywanie zmiennej obiektowej do aplikacji Aby przypisać odwołanie do obiektu do zmiennej, używamy słowa kluczowego Set. Przykładowo: Set objExcel = Excel.Application Zmienne obiektowe przechowują wskaźnik do obiektu. Gdy zmienna obiektowa zostanie przypisana do aplikacji Excel, zawiera ona wskaźnik do aplikacji, a nie przechowuje całej aplikacji Excel. Gdy obiekty są przekazywane z jednej procedury do drugiej, są one zawsze przekazywane przez „referencję”, a nie przez „wartość”. Tworzenie egzemplarza aplikacji Jeżeli aplikacja nie pracuje lub chcesz utworzyć nowy egzemplarz obiektu, użyj słowa kluczowego New. Poniższy przykład tworzy nowy egzemplarz aplikacji Word. ' Deklaracja zmiennej objWord Dim objWord As Word.Application ' Tworzenie nowego egzemplarza aplikacji Word Set objWord = New Word.Application Zawsze pisz wyrażenia Dim i Set w osobnych wierszach programu. Nie łącz ich razem w jednym wierszu w następujący sposób: Dim objWord = New Word.application Jeżeli użyjesz takiej deklaracji, program będzie wykonywał się wolniej, a Ty nie będziesz wiedział, kiedy zostanie utworzony obiekt. Jednoczesne użycie funkcji GetObject i New Jeżeli aplikacja jest uruchomiona, użyj jej, nie otwieraj kolejnego egzemplarza. Jeżeli nie jest uruchomiona, uruchom ją. Aby zrealizować taki scenariusz, użyj funkcji GetObject, aby sprawdzić, czy aplikacja pracuje, i słowa kluczowego New, aby ją uruchomić w razie potrzeby. ' Jeżeli Word pracuje, użyj go. Jeżeli nie, uruchom go. ' Deklaracja zmiennej obiektowej objWord Dim objWord As Word.Application ' Gdy Word nie jest uruchomiony, wystąpi błąd. Ignorujemy go. On Error Resume Next ' Próba odwołania się do pracującego Worda. Set objWord = GetObject(, "Word.Application") ' Jeżeli zmienna objWord ma wartość Nothing (nieutworzona ' zmienna obiektowa), Word nie jest uruchomiony If objWord Is Nothing Then ' Utwórz egzemplarz aplikacji Set objWord = New Word.Application ' Jeżeli objWord nadal zawiera "Nothing" MS Word 9.0 ' nie jest zainstalowany. If objWord Is Nothing Then MsgBox "MS Word 2000 nie jest zainstalowany" End If End If ' On Error GoTo ErrorNandler (Tu wstaw obsługę błędów) Słowo kluczowe New może być użyte, gdy tworzysz odwołanie do biblioteki typów aplikacji. Użycie wczesnego i późnego łączenia typów Zauważ, że zmienna obiektowa w wyrażeniu Dim i Set odwołuje się do Word.Application. Taka deklaracja nazywana jest wczesnym łączeniem typów. W czasie kompilacji zmienna obiektowa jest wiązana z biblioteką typów Worda. Skutkuje to szybszym wykonywaniem tak napisanego fragmentu kodu, ponieważ większość czynności została wykonana w trakcie kompilacji, a nie w trakcie wykonania. Jeżeli zmienna objWord zostanie zadeklarowana jako Object, łączenie z biblioteką typów Worda nastąpi w trakcie wykonania programu, co znacznie spowolni program. Przykład poniższy przedstawia oba podejścia: ' Użycie wczesnego łączenia typów. Program jest szybszy. Dim objWord as Word.Application ' Późne łączenie typów, taki program wykonuje się wolniej. Dim objWord as Object W pliku Automation.mdb załączonym do rozdziału 19., znajdują się przykłady testów wydajności, które pokazują znaczną różnicę szybkości między wczesnym i późnym łączeniem typów. Użycie funkcji CreateObject Aby uzyskać najwydajniejszy kod Automation, deklarujemy zmienne obiektowe jako obiekty specyficznych typów (wczesne łączenie), używamy funkcji GetObject, aby sprawdzić czy aplikacja jest uruchomiona i przy użyciu New tworzymy egzemplarz aplikacji w razie potrzeby. Niestety, w niektórych przypadkach nie można użyć wczesnego łączenia typów lub słowa kluczowego New. W takich okolicznościach może być pomocna funkcja CreateObject. Kiedy nie można uzyskać odwołania do aplikacji Gdy używamy Automation z niektórych aplikacji (na szczęście nie z Accessa), nie można utworzyć odwołania do innej aplikacji (nie da się uzyskać odwołania do okna dialogowego). Przykładem jest Outlook 97/98 i aplikacje dla Internetu. W takich wypadkach zmuszony jesteś użyć późnego łączenia typów i użycia funkcji CreateObject. Przykład poniższy zawiera kod Automation, który należy użyć w programie Outlook, aby automatyzować Word. Możesz używać funkcji GetObject, aby sprawdzić, czy jest uruchomiony Word. Funkcja CreateObject tworzy nowy egzemplarz aplikacji. ' Deklaracja objWord jako zmiennej obiektowej. Dim objWord As Word.Application ' Gdy Word nie jest uruchomiony, wystąpi błąd. Ignorujemy go. On Error Resume Next ' Próba odwołania się do pracującego Worda. Set objWord = GetObject(, "Word.Application") ' Wystąpi błąd nr 429, jeżeli Word NIE pracuje If Err.Number = 429 Then Err.Number = 0 ' Utwórz nowy egzemplarz aplikacji Set objWord = Create0bject("Word.Application") ' Gdy znowu wystąpi błąd 429, MS Word 9.0 nie jest zainstalowany. If Err.Number = 429 Then MsgBox "MS Word 2000 nie jest zainstalowany" End If End If ' On Error GoTo ErrorHandler (Tu wstaw obsługę błędów) Co wtedy, gdy użytkownik ma inną wersję aplikacji? W niektórych firmach użytkownicy mogą mieć zainstalowane różne wersje aplikacji. Niektórzy mogą używać Word 95 inni Word 97, podczas gdy jeszcze inni używają Worda 2000. Niektórzy z nich mogą mieć nawet zainstalowanych kilka wersji Worda! Do funkcji CreateObject można przekazać w parametrze, którą wersję aplikacji ma ona utworzyć. Przykład poniżej przedstawia użycie CreateObject w celu uruchomienia Worda 97. ' Deklaracja zmiennej obiektowej objWord Dim objWord As Word.Application ' Tworzenie egzemplarza aplikacji Word 97 Set objWord = Create0bject("Word.Application.8") Numer wersji Office 95 to 7.0, Office 97 to 8.0, a Office 2000 to 9.0. Możesz także przesyłać numer wersji przy użyciu New. Użycie metod i właściwości obiektów automatyzacji Po utworzeniu egzemplarza obiektu aplikacji możesz używać go w swoich programach, korzystając z metod i właściwości obiektu. Ustawianie właściwości obiektu Teraz możesz korzystać z innych aplikacji, używając ich możliwości w swojej aplikacji. Tak samo jak korzystasz z właściwości obiektu z Accessa, możesz używać właściwości obiektów automatyzacji. Poniższy przykład używa właściwości w Wordzie i Excelu: ' Ustawianie właściwości obiektów Automation objWord.Visible = True objExcel.Cells(1,1).Value = "Sprzedaż roczna" Wykonywanie metod obiektów Używając automatyzacji, można wykonywać metody obiektów. Przykład: ' Wykonywanie metod Add obiektów. objWord.Documents.Add objExcel.Workbooks.Add Zwalnianie obiektów automatyzacji Gdy zakończyłeś pracę na zmiennej obiektowej, należy ją zwolnić, przypisując jej wartość Nothing. Zasoby zajmowane przez zmienną zostaną wtedy zwolnione. Właściwa składnia przedstawiona jest na przykładzie: ' Zwalnianie zmiennej obiektowej Set objWord = Nothing Gdy deklarujesz zmienną obiektową, od razu przejdź na dół procedury i przypisz jej wartość Nothing. Zabezpieczy Cię to przed tym, że zapomnisz zwolnić zmienną obiektową po napisaniu długiej procedury. Łączymy wszystko razem Przedyskutowaliśmy wszystkie kroki potrzebne do uruchomienia automatyzacji w aplikacji. Teraz spójrzmy na przykład programu, który łączy te kroki ze sobą. Przykład ten drukuje dokument Worda za pomocą automatyzacji. Przykład zawiera wszystkie kroki przedstawione do tej pory: tworzenie lub pobranie odwołania do Worda, użycie obiektów Worda (a dokładniej metody PrintOut) oraz zwolnienie obiektu automatyzacji. ' Deklaracja zmiennej obiektowej objWord Dim objWord As Word.Application ' Gdy Word nie jest uruchomiony, wystąpi błąd. Ignorujemy go. On Error Resume Next ' Pobranie odwołania do obiektu aplikacji Word Set objWord = GetObject(, "Word.Application") ' Jeżeli zmienna objWord ma wartość Nothing (nieutworzona ' zmienna obiektowa), Word nie jest uruchomiony If objWord Is Nothing Then ' Create a new instance of the Word application. Set objWord = New Word.Application ' Jeżeli objWord nadal zawiera "Nothing" MS Word 9.0 ' nie jest zainstalowany. If objWord Is Nothing Then MsgBox "MS Word 2000 nie jest zainstalowany" End If End If ' On Error GoTo ErrorHandler (Tu wstaw obsługę błędów) ' Otwórz dokument Worda objWord.Documents.Open ("C:\Automation\Northwind Magazine Ad.doc") ' Wydrukuj dokument Worda objWord.PrintOut Background:=False ' Zamknij aplikację Word objWord.Quit ' Zwolnij zmienną obiektową Set objWord = Nothing Jest to bardzo prosty przykład. Rozdział 19. zawiera bardziej skomplikowane programy używające automatyzacji, a także plik Automation.MDB zawierający tysiące wierszy kodu automatyzacji, który możesz użyć w Twoich aplikacjach. Zamykanie aplikacji serwera automatyzacji Podczas nauki tworzenia sesji automatyzacji mogłeś użyć uruchomionego wcześniej egzemplarza aplikacji lub uruchomić nowy egzemplarz. Ważne jest, aby zamykać serwer automatyzacji pod odpowiednimi warunkami. Jeżeli aplikacja działa, gdy uruchamiasz sesję automatyzacji i używasz tego egzemplarza aplikacji, nie zamykaj aplikacji podczas kończenia sesji. Użytkownicy będą bardzo sfrustrowani, jeżeli ich aplikacja zostanie zakończona przez Twój program. Jeżeli utworzyłeś nowy egzemplarz aplikacji, powinieneś zamknąć go po zakończeniu pracy. Jeżeli tego nie zrobisz, aplikacja pozostanie otwarta, nieużywana przez użytkownika, ale zajmująca cenne zasoby systemu. Aby zakończyć aplikację, użyj właściwej metody dla aplikacji. Przykładowo, dla Excela wywołaj metodę Quit, tak jak pokazane jest na przykładzie: ' Zamknij aplikację Excel poprzez wywołanie jej metody Quit. objExcel.Quit Użycie właściwości UserControl do sprawdzenia, w jaki sposób została otwarta aplikacja Właściwość UserControl umożliwia sprawdzenie, czy aplikacja lub dokument został utworzony lub otwarty przez użytkownika, czy w sposób programowy. Jeżeli właściwość UserConrol (zmienna logiczna) zawiera wartość true, aplikacja lub dokument został otwarty przez użytkownika. Jeżeli zawiera false, aplikacja lub dokument został otwarty programowo. Przykład poniższy otwiera Worda i sprawdza, w jaki sposób został otwarty, używając właściwości UserControl. ' Deklaracja zmiennej obiektowej objWord. Dim objWord As Word.Application ' Otwarcie programowe Worda. Set objWord = New Word.Application ' Sprawdzenie właściwości UserControl, aby stwierdzić, czy Word ' został otwarty programowo, czy przez użytkownika If objWord.Application.UserControl Then MsgBox "Word został otwarty przez użytkownika" Else MsgBox "Word został otwarty programowo". End If Set objWord = Nothing Użycie WithEvents w celu udostępnienia zdarzeń serwera automatyzacji Użycie automatyzacji w sposób pokazany do tej pory można porównać do jednostronnej rozmowy telefonicznej. Access kontrolował Worda i nakazywał wykonanie pewnych czynności. Przez użycie klauzuli WithEvents możesz utworzyć dwukierunkową komunikację pomiędzy Accessem i Wordem. Access może zlecać do Worda drukowanie dokumentu lub raportu, Word natomiast odpowiada Accessowi po wystąpieniu odpowiedniego zdarzenia. Na początku należy sprawdzić, jakie zdarzenia są udostępniane przez aplikację. Najprostszą metodą dowiedzenia się tego, jest użycie narzędzia Object Browser. Po wybraniu obiektu aplikacji możesz przeglądać udostępniane zdarzenia. Word 97 posiada tylko dwa zdarzenia udostępniane przez obiekt Application (DocumentChange i Quit). Word 2000 ma 12 zdarzeń udostępnianych przez obiekt Application. Są one pokazane na rysunku 18.4 w Object Browser. Gdy przeglądamy zawartość obiektów, różne ikony wskazują właściwości (palec wskazujący kartkę papieru), metody (zielona latająca gumka) i zdarzenia (błyskawica). Rysunek 18.4. Object Browser pokazujący zdarzenia udostępnione przez Microsoft Word 2000 Microsoft Excel udostępnia więcej zdarzeń niż Word. Obiekt aplikacji Excel 2000 posiada 21 zdarzeń (rysunek 18.5). Rysunek 18.5. Object Browser pokazujący zdarzenia udostępnione przez Microsoft Excel 2000 Uruchamiamy WithEvents Normalnie, gdy używamy automatyzacji w procedurze, deklarujesz zmienną obiektową w następujący sposób: Dim objWord as Word.application Aby użyć WithEvents, usuń deklarację zmiennej z procedury i zamiast niej utwórz zmienną modułową. Słowo kluczowe Dim powinieneś zmienić na Private lub Public. Należy również dodać klauzulę WithEvents, aby udostępnić zdarzenia aplikacji. ' Deklaracja zmiennej modułu używająca klauzuli WithEvents Private WithEvents objWord as Word.Application Klauzula WithEvents może być używana tylko w modułach klasowych (moduł formularza jest modułem klasowym). WithEvents nie może być używane w zwykłych modułach. Rysunek 18.6 przedstawia w jaki sposób zadeklarować zmienną modułową z użyciem klauzuli WithEvents. Rysunek 18.6. Deklaracja zmiennej modułowej przy użyciu klauzuli WithEvents Po zadeklarowaniu zmiennej modułowej przy użyciu klauzuli WithEvents sprawdź zawartość list wyboru na górze okna modułu. W liście wyboru z lewej strony okna wybierz zadeklarowaną wcześniej zmienną, która reprezentuje serwer automatyzacji. W prawej liście wyboru zobaczysz zdarzenia udostępniane przez aplikację. Po wybraniu zdarzenia w oknie programowania pojawia się szkielet procedury, która jest wywoływana po zajściu zdarzenia. Możesz teraz wypełnić tę procedurę kodem wykonywanym w odpowiedzi na zdarzenie. Na rysunku 18.7 pokazane są procedury używające udostępnionych przez Worda zdarzeń DocumentChange i Quit. Rysunek 18.7. Procedury używające udostępnionych zdarzeń programu Microsoft Word Techniki i wskazówki do automatyzacji Od dawna automatyzacja nie ma dobrej opinii z powodu słabej wydajności. Używając rozsądnego sprzętu i właściwych technik kodowania, automatyzacja może pracować wydajnie. Zapamiętaj poniższe porady, gdy będziesz programował automatyzację. Ustanowienie odwołania, użycie wczesnego wiązania typów i słowa kluczowego New Aby rozpocząć sesję automatyzacji, ustaw odwołanie do aplikacji w oknie dialogowym odwołań. Używaj szczegółowych klas w trakcie deklaracji zmiennych obiektowych oraz słowa kluczowego New, aby utworzyć egzemplarz obiektu aplikacji. Wszystkie te zagadnienia były już wcześniej omawiane. Użycie istniejącego egzemplarza aplikacji, jeżeli jest ona uruchomiona Nie otwieraj nowego egzemplarza aplikacji w każdej sesji automatyzacji. Jeżeli aplikacja jest uruchomiona, użyj istniejącego egzemplarza w sesji automatyzacji. Wyłącz odświeżanie ekranu Podczas typowej sesji automatyzacji z użyciem Excela czy Worda następuje ogromna ilość odświeżeń ekranu. Zawsze, gdy ważna jest dla nas wydajność, przełączaj ScreenUpdating na False. Wydajność się polepszy, gdyż nie będzie konieczne odświeżanie ekranu. Najlepszą techniką jest przełączenie ScreenUpdating na False, wykonanie pracy przez automatyzację i na koniec przełączenie ScreenUpdating na True. Użytkownik zobaczy kompletny dokument, kiedy zostanie wykonany. Poniższy przykład przedstawia tę technikę. ' Wyłącz odświeżanie ekranu Application.ScreenUpdating = False ' Tutaj jest przetwarzanie przez automatyzację ' Włącz odświeżanie ekranu Application.ScreenUpdating = False Pewnego razu omyłkowo zainstalowałem użytkownikom aplikację z włączonym odświeżaniem ekranu, co spowalniało aplikację. W następnej wersji odświeżanie zostało wyłączone. Dostałem tak wiele skarg od użytkowników, że dokonałem korekty i dałem im wersję znowu z włączonym odświeżaniem ekranu. Użytkownicy wyjaśniali, że gdy był odświeżany ekran, mieli możliwość przeczytania dokumentu, rozpoczęcia korekty lub upewnienia się, że wybrali właściwy dokument do druku. Przez zmuszenie użytkowników do czekania aż cały dokument będzie gotowy, tracili oni trzy do pięciu sekund czasu poświęcanego na korektę. Uważali również, że jest to coś ciekawego, oglądać jak dokument jest tworzony fragment po fragmencie w „magiczny” sposób. Zatem należało tu rozpatrzyć „czas przetwarzania” człowieka przy przeglądaniu dokumentu, a nie tylko czas przetwarzania komputera. Informacja o przetwarzaniu Jeżeli sesja automatyzacji trwa przez dłuższy czas, na pewno musisz informować użytkownika o trwającym procesie. Można użyć paska postępu, klepsydry jako kursora myszy lub innego graficznego wskaźnika. Jeżeli tego nie zrobisz, użytkownik może pomyśleć, że komputer się zawiesił i wyłączyć go. Pamiętaj, że w pracy poprzez automatyzację uruchomiona jest więcej niż jedna aplikacja, więc niszczące skutki takiego wyłączenia mogą być znaczne. Jako programista wiesz, że wyświetlanie informacji w trakcie przetwarzania spowalnia sam proces przetwarzania. Jednak ważniejszy jest nie całkowity czas, jaki zajmie ukończenie procesu, ale czas „widziany”. Użytkownicy uważają, że przetwarzanie trwa krócej, gdy widoczne są wskaźniki zaawansowania procesu, choć naprawdę trwa to nieco dłużej. Tworzyłem aplikację dla firmy lotniczej, która wymagała wykonania skomplikowanego kodu automatyzacji Excela. W trakcie przetwarzania mała ikona samolotu przesuwała się po ekranie. Użytkownicy byli bardziej zainteresowani tym małym samolocikiem lecącym przez ich ekran niż skomplikowanym programem wykonującym dla nich pracę. Wykonywanie programu przez serwer automatyzacji Program zawsze działa szybciej, jeżeli serwer automatyzacji wykonuje swój kod. Przykładowo, jeżeli Twoja aplikacja Accessa używa Worda, na początku utwórz egzemplarz obiektu dokumentu Worda. Następnie umieść cały kod VBA, który zajmuje się manipulowaniem Wordem (zmiany czcionek lub stylu tekstu, drukowanie dokumentu) w Wordzie. Inaczej mówiąc, niech aplikacja uruchamia własny kod. Jeżeli używane są obiekty, właściwości i metody Worda, umieść je w kodzie VBA w Wordzie. W przeciwnym wypadku komunikacja między procesami Accessa i Worda będzie nawiązywana dla każdego wyrażenia w kodzie programu. Używając tej techniki, istotnie polepszysz wydajność. Kod VBA w aplikacjach Word i Excel umieszczony jest w szablonach. Aby ułatwić rozprowadzanie szablonów, umieść je w udostępnionym katalogu na serwerze plików. W menu Narzędzia, Opcje, na zakładce Położenie plików można ustawić położenie szablonów grupy roboczej na ten sieciowy katalog. Gdy potrzebne są zmiany w kodzie lub dodajesz nowy szablon, kopiujesz pliki tylko do jednego katalogu na serwerze. Użycie konstrukcji With/End With Są dwa powody, aby używać konstrukcji With/End With. Po pierwsze, kod działa szybciej, ponieważ odwołanie do obiektu jest wykonywane tylko raz. Drugi powód to czytelność kodu. Pomyśl o każdej kropce jak o ograniczniku prędkości na drodze. Im mniej kropek, tym lepiej! Porównaj dwa poniższe przykłady: Przykład 1. Odwołanie do obiektu jest wykonywane w każdym wierszu kodu, co powoduje jego spowolnienie. Kod jest trudniejszy do czytania. objExcel.Range("F6").Select objExcel.ActiveCell.FormulaRlC1 = "Sprzedaż roczna" objExcel.Range("G6").Select objExcel.ActiveCell.FormulaRlC1 = "Podsumowanie sprzedaży" objExcel.Range("F7").Select Przykład 2. Odwołanie do obiektu jest wykonywane tylko raz, co powoduje przyspieszenie kodu. Łatwiej się go czyta. With objExcel .Range("F6").Select .ActiveCell.FormulaRlC1 = "Sprzedaż roczna" .Range("G6").Select .ActiveCell.FormulaRlC1 = "Podsumowanie sprzedaży" .Range("F7").Select End With Zwalnianie zmiennych obiektowych Tak jak wcześniej o tym mówiliśmy, zawsze zwalniaj zmienne obiektowe na końcu sesji automatyzacji przez przypisanie im wartości Nothing, aby odzyskać zasoby. Nie wyświetlaj okien dialogowych i komunikatów Unikaj operacji, które zatrzymują sesję automatyzacji, takich jak okna dialogowe lub okna komunikatów. Jeżeli nastąpi zatrzymanie, może nie być widoczne przez użytkownika, ponieważ inna aplikacja posiada w tym czasie fokus. Używaj obsługi błędów Automatyzacja komplikuje Twoje aplikacje. Zalety użycia właściwości innych aplikacji są ograniczane przez to, że więcej rzeczy może źle zadziałać. Istotne jest, aby obsłużyć wszystkie błędy, które mogą zdarzyć się w trakcie sesji automatyzacji. W aplikacjach Microsoft Office aplikacja serwera może zwracać informacje o błędach. Popatrz do rozdziału 13. „Profesjonalna obsługa błędów”, aby znaleźć informacje na temat obsługi błędów. Rozdział 19. Integracja z Office 2000 W tym rozdziale: ? Powody integracji z Office 2000. ? Wybór właściwego narzędzia. ? Wszędzie VBA. ? Użycie rejestratora makr do pisania kodu. ? Użycie makr automatycznych. ? Microsoft Forms. ? Object Browser. ? Nazwy klas aplikacji Office. ? Przykład Automation. ? Automatyzacja Worda. ? Automatyzacja Excela. ? Automatyzacja PowerPoint. ? Automatyzacja Outlooka. ? Automatyzacja Graph. ? Automatyzacja MapPoint. ? Automatyzacja FrontPage. ? Automatyzacja Binder. ? Zabezpieczanie dokumentów, szablonów i kodu. W poprzednim rozdziale zostały przedstawione zasady i techniki użycia automatyzacji. Teraz zastosujemy tę wiedzę, używając wszystkich aplikacji w pakiecie Microsoft Office 2000. W rozdziale tym zapoznamy się ze sposobami użycia w Accessie innych aplikacji firmy Microsoft, takich jak: Word, Excel, PowerPoint, Outlook, Graph, MapPoint, FrontPage oraz Binder. Zajrzyj do przykładów kodu dla tego rozdziału. Jest tam wiele wierszy kodu automatyzacji dla programistów Access, Excel, PowerPoint, Outlook, Graph, FrontPage i MapPoint (rysunek 19.1). Rysunek 19.1. Plik Automation.MDB Powody integracji z Office 2000 Office 2000 jest pełnym pakietem produktów będącym odpowiedzią na oczekiwania i potrzeby klientów. Produkty te oferują ogromną ilość opcji, które zostały napisane i przetestowane przez Microsoft. Office 2000 udostępnia setki obiektów, którymi programista może manipulować przy użyciu VBA. Żaden inny pakiet biurowy w chwili obecnej nie zapewnia takiej siły i integracji, jaką oferuje Office 2000. Aby utworzyć kompletną aplikację, możesz użyć wielu możliwości aplikacji Office 2000 opisanych poniżej. Użycie Worda Word jest doskonałym wyborem, aby tworzyć faktury, listy, notatki i raporty. Word jest wspaniałym edytorem raportów. Jako programista, możesz tworzyć ozdobne dokumenty w Accessie lub Excelu, ale czemu ponosić taki wysiłek? Word ma wszystkie style i możliwości formatowania, jakich kiedykolwiek będziesz potrzebował. Użycie Excela Jeżeli potrzebujesz przetwarzać liczby, Excel jest świetnym wyborem. Możesz tworzyć imponujące wykresy i diagramy na spotkania służbowe, negocjacje z klientami, zebrania rady nadzorczej itp. Użycie PowerPoint Gdy przychodzi czas na pokaz, użyj PowerPoint. Robiące wrażenie, wysokiej jakości prezentacje mogą być utworzone relatywnie łatwo. Utwórz efektywne demonstracje dla sprzedaży produktów, zebrań personelu lub dyrekcji, prezentacje dla inwestorów itp. Użycie Outlooka Outlook dostarcza licznych funkcji, które możesz włączyć do Twojej aplikacji. Użyj poczty Outlooka do poczty korporacyjnej, internetowej, automatycznej wysyłki zamówień do działów ekspedycji, automatycznego zamawiania produktów w razie potrzeb, fakturowania klientów i innych funkcji. Zamiast tworzyć kalendarz w swojej aplikacji, możesz podłączyć się do tej funkcji z Outlooka. Pracownicy mogą prowadzić swoje kalendarze, jak również kalendarze biurowe. Outlook zapewnia zarządzanie zadaniami, które mogą być użyte do stworzenia list zadań do wykonania przez pracowników, listy zadań do wykonania przez oddział, specjalnych projektów, itd. Kontakty Outlooka umożliwiają utworzenie prywatnych list adresowych, jak również wspólnych dla biura. Oczywiście bazę zarządzania kontaktami można utworzyć w Accessie, ale Outlook jest gotowy do użycia natychmiast. Użycie Graph Microsoft Graph jest użytecznym narzędziem do tworzenia wykresów w Accessie i innych aplikacjach Office. Użycie MapPoint MapPoint jest narzędziem do szukania i wyświetlania informacji na mapach. Za pomocą automatyzacji adres może być odczytany z bazy danych, a następnie zostanie wyświetlona mapa przedstawiająca dokładne położenie adresu. Użycie FrontPage Sieć jest istotna w dzisiejszym świecie biznesu. Użyj FrontPage do tworzenia i modyfikacji stron WWW oraz do innych zastosowań sieciowych. Użycie Bindera Office Binder dostarcza sposobu integracji dokumentów Office za pomocą zunifikowanego narzędzia. Za pomocą automatyzacji dokumenty Worda, Excela i PowerPointa mogą być łączone w Binderze, więc użytkownicy będą mogli pracować z wszystkimi dokumentami jednocześnie. Wszystkie dokumenty mogą być zapisane w formacie Bindera, więc kiedykolwiek użytkownik będzie chciał pracować na nich znowu, to otworzy Binder, gdzie wszystkie te dokumenty będą w wygodny sposób dostępne. Wybór właściwego narzędzia Pierwszym i prawdopodobnie najistotniejszym wyborem, jakiego dokonano programista, jest odpowiedź na pytanie „Jakiego narzędzia powinienem użyć do stworzenia tej opcji?”. Przeciwstaw się pokusom stworzenia wszystkiego w Accessie, ponieważ najlepiej znasz tę aplikację. VBA jest teraz dostępny we wszystkich produktach Office. Teraz jest dużo łatwiej niż kiedyś przestawić się na Worda czy Excela i szybko poczuć się komfortowo w czasie programowania. Pomyśl o automatyzacji jak o zestawie usług, które możesz włączyć do swojej aplikacji: ? Access – usługi baz danych. ? Word – edycja tekstu i usługi małej poligrafii. ? Excel – obliczenia i usługi finansowe. ? PowerPoint – prezentacje ? Outlook – poczta, kalendarz, kontakty, zadania i inne usługi. ? Graph – wykresy i schematy. ? MapPoint – usługi związane z mapami. ? FrontPage – usługi tworzenia stron internetowych. ? Binder – usługi łączenia dokumentów. Wszędzie VBA Visual Basic for Applications (VBA) jest potężnym językiem programowania, który istnieje wewnątrz programów Office. Ta unifikacja języka programowania pozwala programistom na łatwe łączenie aplikacji Office w zunifikowane rozwiązania programowe. Użycie rejestratora makr do pisania kodu Rejestrator makr jest doskonałym generatorem kodu i może być użyty do błyskawicznego programowania w Wordzie, Excelu i PowerPoincie. Aby uruchomić rejestrator makr w tych aplikacjach, wybierz Makro z menu Narzędzia, a następnie Zarejestruj nowe makro (rysunek 19.2). Rysunek 19.2. Okno dialogowe rejestratora makr Po wywołaniu rejestratora makr, wpisz nazwę makra i naciśnij OK, aby rozpocząć proces rejestracji. Na ekranie widoczny będzie mały pasek narzędzi zawierający dwa przyciski. Przesuwając kursor myszy nad tymi przyciskami, możesz zobaczyć, że jest to zatrzymanie i pauzowanie rejestrowania. Dodatkowo, aby zasygnalizować, że działa rejestrator makr, przy kursorze myszy widoczna jest mała kaseta magnetofonowa (rysunek 19.3). Rysunek 19.3. Dokument Worda z pracującym rejestratorem makr W czasie pracy rejestratora wszystkie czynności, jakie wykonasz zostaną skonwertowane do kodu VBA. Możesz wpisywać tekst do dokumentu, formatować go a nawet zapisywać i drukować. Gdy zakończysz czynności, które miały być zarejestrowane, naciśnij przycisk Zatrzymaj rejestrowanie. Aby zobaczyć kod VBA, jaki został zapisany przez rejestrator, wybierz Makro z menu Narzędzia i z następnego menu Makra. Wybierz zapisane przez siebie makro i naciśnij przycisk Edytuj. Otworzy się edytor VBA, pokazując kod realizujący makro (rysunek 19.4). Rysunek 19.4. Kod VBA wygenerowany przez rejestrator makr w edytorze VBA Rejestrator makr nie zawsze generuje optymalny kod, więc zawsze należy go przejrzeć przed użyciem w aplikacji. Dodanie konstrukcji With/ End With jest również dobrym pomysłem. Użycie makr automatycznych Word, Excel i PowerPoint zawierają mechanizm makr automatycznych. Mogą być one użyte do uruchamiania programu po zajściu określonych zdarzeń. Przykładowo, w Wordzie istnieją następujące makra automatyczne: ? AutoExecute – jest wykonywane w czasie uruchamiania Worda; ? AutoNew – jest wykonywane podczas tworzenia nowego dokumentu; ? AutoOpen – jest wykonywane podczas otwierania dokumentu; ? AutoClose – jest wykonywane podczas zamykania dokumentu; ? AutoExit – jest wykonywane podczas zamykania Worda. Aby użyć tych makr należy za pomocą VBA utworzyć w module funkcję o nazwie odpowiedniego makra automatycznego. Przykładowo, aby utworzyć makro automatyczne AutoOpen, powinieneś utworzyć taką procedurę: Private/Public Sub AutoOpen () ' Kod wykonywany podczas otwierania dokumentu End Sub Microsoft Forms Programy Office: Word, Excel i PowerPoint używają oddzielnego modułu formularzy Microsoft Forms. Niekiedy, gdy używasz innych aplikacji, takie formularze mogą się przydać. Doświadczeni programiści Accessa nie będą mieli trudności w użyciu Microsoft Forms. Tworzenie formularza, używając Microsoft Forms, przebiega według następującego scenariusza. Z menu Insert wybierz User Form lub naciśnij Shift+F7. Używając paska narzędzi, dodaj na formularz formanty. Napisz obsługę komunikatów formularza i formantów, używając VBA. Do formularza takiego można również dodać formanty ActiveX. Microsoft Forms są oddzielne od formularzy Accessa, Visual Basica i Outlooka. Jest to osobny pakiet. Nie można konwertować formularzy Accessa do Microsoft Forms i odwrotnie Object Browser Gdy pracujesz z różnymi aplikacjami omawianymi w tym rozdziale, nie zapominaj o użyciu narzędzia Object Browser. W poprzednim rozdziale szczegółowo omówiłem, jak go używać. Aby wywołać Object Browser, w oknie edytora VBA wybierz Object Browser z menu View lub naciśnij F2 (rysunek 19.5). Rysunek 19.5. Object Browser wyświetlający obiekty Worda Nazwy klas aplikacji Office Aby użyć innych aplikacji Office, musisz znać nazwy klas występujących w tych aplikacjach: Aplikacja Nazwa klasy Access Access.Application Binder Office.Binder Excel Excel.Application Excel.Sheet Excel.Chart FrontPage FrontPage.Application Graph Graph.Application MapPoint MapPoint.Application Outlook Outlook.Application PowerPoint PowerPoint.Application Word Word.Application Word.Document Przykład automatyzacji Podstawy automatyzacji (przykładowo dla Worda: tworzenie lub pobieranie odwołania do Worda, użycie obiektów Worda, zwalnianie obiektu) zostały przedstawione w poprzednim rozdziale. Przykład poniższy drukujący informacje o Accessie w postaci dokumentu Worda ilustruje wszystkie wymienione kroki. Nie zapomnij ustawić wcześniej odwołania do Worda. Private Sub AccessApplicationReport() Dim objWord As Word.Application DoCmd.Hourglass True ' Przejdz do następnego wiersza w przypadku błędu On Error Resume Next ' Próba pobrania odwołania do pracującego Worda Set objWord = GetObject(, "Word.Application") ' Word nie działa If objWord Is Nothing Then ' Utwórz nowy egzemplarz Worda Set objWord = New Word.Application ' Jeżeli objWord jest Nothing to znaczy, że nie da się ' uruchomić Worda If objWord Is Nothing Then MsgBox "MS Word 8.0 nie jest zainstalowany" End If End If ' On Error GoTo ErrorHandler (Tu wstaw obsługę błędów) ' Otwórz nowy dokument oparty na szablonie Normal.dot objWord.Documents.Add ' Przełączenie się na Worda objWord.Activate ' Pokazujemy Worda użytkownikowi objWord.Visible = True ' Tworzenie nagłówka raportu With objWord.Selection .TypeText vbTab & vbTab & "Raport o aplikacji Accessa" .StartOf Unit:=wdStory, Extend:=wdExtend .Font.Bold = True .Font.Size = 20 .EndKey Unit:=wdLine .TypeParagraph .TypeParagraph .Font.Bold = False .Font.Size = 16 End With ' Wstaw informacje o tej aplikacji Accessa do dokumentu Worda With objWord.Selection .TypeText "Obiekt aplikacji" & vbTab & "Wartość" & vbCrLf .TypeText "Nazwa i ścieżka do bazy" & vbTab & _ Application.CurrentDb.Name & vbCrLf .TypeText "Nazwa bieżącego formularza" & vbTab & _ Forms.Item(0).Name & vbCrLf .TypeText "Nazwa bieżącego obiektu" & vbTab & _ Application.CurrentObjectName & vbCrLf .TypeText "Nazwa bieżącego użytkownika" & vbTab & _ Application.CurrentUser & vbCrLf .TypeText "Wersja Jet" & vbTab & _ Application.DBEngine.Version & vbCrLf .TypeText "Kompilacja aplikacji" & vbTab & _ Application.IsCompiled & vbCrLf .TypeText "Ilość odwołań" & vbTab & _ Application.References.Count & vbCrLf .TypeText "Kursor myszy" & vbTab & _ Application.Screen.MousePointer & vbCrLf .TypeText "User Control" & vbTab & Application.UserControl & _ vbCrLf .TypeText "Widoczność aplikacji" & vbTab & Application.Visible & _ vbCrLf .StartOf Unit:=wdStory .MoveDown Unit:=wdLine, Count:=2 .StartOf Unit:=wdLine .EndOf Unit:=wdStory, Extend:=wdExtend .ConvertToTable Separator:=wdSeparateByTabs, NumColumns:=2, _ NumRows:=11, Format:=wdTableFormatColorful2, _ ApplyBorders:=True, ApplyShading _ :=True, ApplyFont:=True, ApplyColor:=True, _ ApplyHeadingRows:=True, ApplyLastRow:=False, _ ApplyFirstColumn:=False, ApplyLastColumn:=False, _ AutoFit:=True, AutoFitBehavior:=wdAutoFitFixed .EndOf Unit:=wdStory End With ' Wyłącz pokazywanie znaków końca akapitu objWord.ActiveWindow.ActivePane.View.ShowAll = False DoCmd.Hourglass False ' Zwolnij obiekt Set objWord = Nothing End Sub Automatyzacja Worda W tej części opiszę specyficzne zagadnienia i przykłady automatyzacji Worda. Model obiektów Worda Poprzedni przykład przedstawia program, zawierający wszystkie operacje potrzebne do automatyzacji. Skupię się teraz na opisie obiektów, właściwości i metod dostępnych w Wordzie. Model obiektów jest w tym względzie bardzo pomocny. Model obiektów jest szablonową reprezentacją obiektów aplikacji. Jest to szybka i łatwa metoda poznania obiektów, które można użyć do programowania. Spójrz do „Obiekty Microsoft Word” w pliku pomocy. Zamieszczony jest tam diagram struktury obiektów w Wordzie. Model Worda jest dosyć obszerny. Zawiera on ponad 180 obiektów dostępnych poprzez VBA. Często używane obiekty Worda zebrane są w tabeli 19.1. Nazwy obiektów, które są kolekcjami mają końcówkę (s). Tabela 19.1. Obiekty Worda Obiekt Worda Opis Application Aplikacja Word. Zwykle nie potrzebujesz odwoływać się do tego obiektu z Worda. Jeżeli używasz Worda z innej aplikacji, musisz użyć tego obiektu AutoCaption(s) Automatycznie dodawane nagłówki AutoCorrect Funkcja Autokorekta Character Znaki w otwartym dokumencie CommandBar(s) Poszczególne paski narzędzi dostępne są poprzez indeks lub nazwę DefaultWebOptions Domyślne ustawienia dla publikowania lub zapisywania jako strona WWW Dialog(s) Okna dialogowe Dictionary(s) Słowniki w Wordzie Document(s) Otwarte dokumenty. Można się do nich odwoływać przez indeks lub nazwę Email Przesyłka e-mail dla dokumentu Tabela 19.1. Obiekty Worda (ciąg dalszy) Obiekt Worda Opis EmailSignature Informacja o podpisie przesyłki e-mail Find Obiekt używany do przeszukiwania słów, zakresów itd. Paragraphs Kolekcja akapitów. Range Zdefiniowany punkt początkowy i końcowy akapitu. Dokument może zawierać kilka zakresów Replacement Obiekt określający warunki zastępowania Selection Zaznaczony tekst. Może być tylko jeden zaznaczony fragment tekstu w dokumencie Table(s) Pojedyncza tabela Template(s) Szablon dokumentu WebOptions Ustawienia nadpisujące DefaultWebOptions Window(s) Okna dokumentów. Poszczególne okna dostępne są przez indeks lub nazwę Words Kolekcja słów Użycie szablonów Worda Jak mówiłem w poprzednim rozdziale, kod automatyzacji działa szybciej, gdy jest wykonywany przez serwer automatyzacji. Inaczej mówiąc, gdy używamy obiektów Worda, kod VBA powinien być umieszczony w szablonie Worda zamiast w Accessie. Aby utworzyć szablon Worda, otwórz nowy dokument Worda. Po wpisaniu potrzebnego kodu VBA wybierz Zapisz jako z menu Plik, aby zapisać ten dokument jako szablon dokumentu (rozszerzenie .DOT). Aby dodać kod do szablonu użyj Rejestratora Makr w sposób omówiony wcześniej. Uruchom Rejestrator, wykonaj czynności które chcesz automatyzować a Rejestrator Makr utworzy dla Ciebie kod VBA. Jak uruchomić kod VBA Worda z Accessa? Jest to bardzo proste. Należy użyć metody Run. ' Uruchom makro w Wordzie formatujące dokument objWord.Run "FormatDocument" Uruchamianie tego makra przez Worda jest dużo szybsze, ponieważ komunikacja między procesami musi zachodzić dla każdej instrukcji automatyzacji. Dzięki umieszczeniu kodu w Wordzie, jest on uruchamiany przez jeden proces. W pliku dołączonym do tego rozdziału znajdują się przykłady używające tego samego kodu automatyzacji w Accessie i przedstawia szablon Worda. Stoper pokazuje różnicę szybkości. Umieszczenie kodu w Wordzie powoduje znaczną różnicę szybkości. Mimo że program działa szybciej, gdy umieścimy go w szablonie Worda, czy nie będzie to sprawiało problemów instalacyjnych? Nie, jeżeli zrobimy to odpowiednio. Szablony można zapisywać na każdej stacji roboczej lub jako szablony grupy roboczej na serwerze. Zaletą zapisywania szablonów do katalogu szablonów grupy jest to, że gdy zmienimy szablon, należy go skopiować tylko do współdzielonego katalogu na serwerze. Jednak, gdy używamy szablonów grupy, następuje komunikacja przez sieć. Niektórzy programiści tworzą proste aplikacje, które kopiują szablony z serwera do każdej stacji roboczej podczas startu aplikacji. Aby zapewnić użytkownikom dostęp do szablonów grupy (na serwerze), wybierz Opcje z menu Narzędzia. Na zakładce Położenie plików wpisz ścieżkę do katalogu szablonów grupy (patrz rysunek 19.6). Rysunek 19.6. Położenie plików w opcjach Worda Wstawianie danych do dokumentu Worda Word jest wspaniałym edytorem raportów. Dane korporacyjne mogą być prezentowane w postaci dokumentów możliwych do modyfikacji przez użytkowników. Poniższy przykład przedstawia gazety reklamowe (rysunek 19.7.). Istnieją trzy sposoby, aby wysłać dane z bazy danych Accessa lub serwera SQL do dokumentu Worda: korespondencja seryjna, zakładki oraz zastępowanie. Przykłady w tym rozdziale używają wszystkich tych sposobów. Korespondencja seryjna Użytkownicy często używają do tworzenia dokumentów korespondencji seryjnej. Można to także zrobić przy użyciu automatyzacji. Preferowaną metodą integracji z Wordem przy użyciu użycia automatyzacji jest korespondencja seryjna. Rysunek 19.7. Tworzenie raportów w Wordzie Aby stworzyć kod automatyzacji korespondencji seryjnej, uruchom rejestrator makr i wykonaj wszystkie kroki, które wykonuje użytkownik w celu utworzenia takiego dokumentu. Wybierz Korespondencja seryjna z menu Narzędzia i zrealizuj wszystkie kroki w pomocniku korespondencji seryjnej. Gdy wybierasz źródło danych do połączenia z dokumentem, możesz wybrać tabelę Accessa lub kwerendę ze źródła danych. Powinieneś wiedzieć, że jeżeli umieścisz dane w pliku RTF i użyjesz tak spreparowanego pliku jako źródło danych, kod automatyzacji będzie działał wyraźnie szybciej. Najważniejszą zaletą korespondencji seryjnej jest to, że użytkownicy mogą wstawiać pola danych do dokumentu. Pozwala to użytkownikom na tworzenie swoich dokumentów, a także odciąża programistów od potrzeby tworzenia raportów. Poprawnie zaprojektowane przez programistę szablony dokumentów zawierają odpowiednie pola danych, na podstawie których użytkownicy mogą utworzyć swoje raporty (rysunek 19.8). Rysunek 19.8. Tworzenie raportów przez użytkowników Przykład procedury uruchamiającej korespondencję seryjną zaczerpnięty z pliku z przykładami do tego rozdziału: Private Sub RunMailMerge() With ActiveDocument.MailMerge .MainDocumentType = wdFormLetters ActiveDocument.MailMerge.OpenDataSource Name:= _ "C:\Automation\Automation.MDB", ConfirmConversions:=False, _ ReadOnly:=False, LinkToSource:=True, AddToRecentFiles:=False, _ PasswordDocument:="", PasswordTemplate:="", _ WritePasswordDocument:= ", WritePasswordTemplate:="", _ Revert:=False, Format:=wdOpenFormatAuto, _ Connection:="QUERY qryEmployeeLetters", SQLStatement:= _ "SELECT * FROM [qryEmployeeLetters]", SQLStatement1:="" .Destination = wdSendToNewDocument .Execute End With End Sub Zakładki Inną metodą wstawiania danych do dokumentów Worda jest użycie zakładek. Zakładka w dokumencie jest oznaczeniem miejsca, gdzie będą wstawione dane. W czasie wykonania programu wyszukiwane są kolejne zakładki i w te miejsca są wstawiane dane. Niedogodnością zakładek jest to, że programista sam musi wstawić zakładki do szablonu i napisać program (lub użyć rejestratora makr) wyszukujący zakładki i wstawiający dane. Użytkownicy nie mogą tworzyć swoich dokumentów z danymi, jak w przypadku użycia korespondencji seryjnej. Inną niedogodnością tej metody jest to, że zakładki nie są widoczne w dokumencie, co utrudnia ich odszukanie i identyfikację. Aby zastosować tę metodę, utwórz szablon Worda i wpisz tekst. Następnie wstaw zakładki w miejsca, gdzie chcesz wstawić dane, wybierając Zakładka z menu Wstaw. Wpisz nazwę zakładki i naciśnij przycisk Dodaj. Użyj rejestratora makr do wygenerowania kodu VBA, przechodząc do zakładki i wpisując tekst. Przykład kodu zamieszczony jest poniżej. Selection.GoTo..... What:=wdGoToBookmark, Name:="MyBookmark" Selection.TypeText "New Text" Zastępowanie Używając tej techniki, tekst jest wstawiany do dokumentu w oznaczone miejsca (np. {Nazwisko}). Program szuka tych oznaczonych miejsc za pomocą funkcji Znajdź i zamienia je na odpowiednie dane. Inaczej mówiąc {Nazwisko} zostanie odszukane i zamienione na „Kowalski”. Zaletą tej metody w porównaniu z zakładkami jest to, że oznaczony tekst jest widoczny i czytelny w porównaniu z zakładką. Jeszcze raz użyj rejestratora makr podczas wyszukiwania i zamiany, aby utworzyć kod VBA. With Selection.Find .ClearFormatting .Text = "{Tekst do odszukania}" .Replacement.Text = "Nowy tekst" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False .Execute Replace:=wdReplaceAll End With Przykłady kodu automatyzacji Worda Poniższe przykłady przedstawiają programy używające specyficzne właściwości i metody obiektów Worda. Formatowanie dokumentów Word ma ogromne możliwości formatowania dokumentów. Do utworzenia i sformatowania dokumentu można użyć następującego fragmentu programu w VBA: ' Formatowanie tekstu With Selection.Font .Size = 14 .Bold = True End With ' Formatowanie akapitu With Selection.ParagraphFormat .LeftIndent = InchesToPoints(0) .RightIndent = InchesToPoints(0) .SpaceBefore = 0 .SpaceAfter = 0 .LineSpacingRule = wdLineSpaceSingle .Alignment = wdAlignParagraphLeft .KeepWithNext = False .KeepTogether = False .PageBreakBefore = False .NoLineNumber = False .Hyphenation = True .FirstLineIndent = InchesToPoints(0) .OutlineLevel = wd0utlineLevelBodyText End With ' Ustawianie podwójnego odstępu między wierszami Selection.ParagraphFormat.LineSpacingRule = wdLineSpaceDouble ' Wstawienie znaku końca strony Selection.InsertBreak Type:=wdPageBreak ' Wstawienie znaku końca sekcji Selection.InsertBreak Type:=wdSectionBreakNextPage Użycie stylów dokumentu Styl to zestaw instrukcji formatowania, który posiada swoją nazwę i może być przypisywany do tekstu. Style umożliwiają formatowanie kilku bloków tekstu lub akapitów jedną instrukcją. Dodatkowo pomagają utrzymać spójność formatowania dokumentu. ' Zastosowanie stylu Nagłówek 1 Selection.Style = ActiveDocument.Styles("Heading 1") ' Tworzenie nowego stylu ActiveDocument.Styles.Add Name:="MyNewStyle", Type:=wdStyleTypeParagraph With ActiveDocument.Styles("MyNewStyle") .AutomaticallyUpdate = False .BaseStyle = "Heading 5" End With With ActiveDocument.Styles("MyNewStyle").Font .Name = "Times New Roman" .Size = 12 .Bold = False .Italic = False .Underline = wdUnderlineSingle .StrikeThrough = False .DoubleStrikeThrough = False .Outline = False .Emboss = False .Shadow = False .Hidden = False .SmallOaps = False .AllCaps = False .ColorIndex = wdAuto .Engrave = False .Superscript = False .Subscript = False .Scaling = 100 .Kerning = 0 .Animation = wdAnimationNone End With Autokorekta Autokorekta poprawia niektóre błędnie napisane słowa (np. „barzdo” zostanie zamienione na „bardzo”). Możesz także użyć autokorekty, aby zaoszczędzić pisania (np. zamienić „MS” na „Microsoft”). Autotekst Autotekst jest bazą danych przechowującą często używane fragmenty tekstu i obiekty graficzne, które mogą być w łatwy sposób wstawiane do dokumentu. W przykładach do rozdziału zamieszczony jest program wstawiający tekst i zdjęcia do dokumentu. ' Tworzenie pozycji w autotekście. NormalTemplate.AutoTextEntries.Add Name:="Microsoft", _ Range:=Selection.Range ' Wstawianie do autotekstu. NormalTemplate.AutoTextEntries("Microsoft").Insert _ Where:= Selection.Range Autopodsumowanie Autopodsumowanie analizuje każde zdanie dokumentu, aby wygenerować podsumowanie. Podsumowanie może być wyświetlane na kilka sposobów: jako wyróżniony tekst w dokumencie, jako streszczenie na początku dokumentu, w nowym dokumencie lub tylko samo podsumowanie. Autopodsumowanie może również tworzyć streszczenia stron WWW. ' Tworzy podsumowanie dokumentu jako nowy dokument. ActiveDocument.AutoSummarize Length:=25, _ Mode:=wdSummaryModeCreateNew, UpdateProperties:=True Widoki dokumentu Po utworzeniu dokumentu trzeba wyświetlić go we właściwej postaci: normalnej, układu dla sieci WWW, układu strony i konspektu. ' Układ normalny ActiveWindow.View.Type = wdNormalView ' Układ sieci WWW ActiveWindow.View.Type = wdOnlineView ' Układ strony ActiveWindow.View.Type = wdPageView ' Układ konspektu ActiveWindow.ActivePane.View.Type =wd0utlineView ' Główny dokument ActiveWindow.ActivePane.View.Type = wdMasterView Spis treści Dawniej tworzenie dokumentu było uciążliwym zadaniem. Teraz w Wordzie jest to zautomatyzowany proces. Aby tworzenie spisu przebiegło sprawnie, należy używać stylów w dokumencie. Gdy zastosujesz style Nagłówek 1, Nagłówek 2 itd., Word w oparciu o te informacje automatycznie utworzy prawidłowy spis treści. ' Tworzenie spisu treści With ActiveDocument .TablesOfContents.Add Range:=Selection.Range, _ RightAlignPageNumbers:= _ True, UseHeadingStyles:=True, UpperHeadingLevel:=1, _ LowerHeadingLevel:=3, IncludePageNumbers:=True, _ AddedStyles:="" .TablesOfContents(1).TabLeader = wdTabLeaderDots End With Przypisy Przypisy pomagają czytelnikowi odnaleźć i ocenić informacje, które odnoszą się do treści zawartych w dokumencie. ' Tworzenie przypisu ActiveDocument.Footnotes.Add Range:=Selection.Range, _ Reference:=Selection, Text:="My New Footnote" Nagłówki Nagłówki są umieszczone na górze każdej strony dokumentu. ' Tworzenie nagłówka ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader Selection.TypeText Text:="My Header" Stopki Stopki umieszczone są na dole każdej strony dokumentu. ' Tworzenie stopki ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader If Selection.HeaderFooter.IsHeader = True Then ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageFooter Else ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader End If Selection.TypeText Text:="My Footer" Hiperłącza Hiperłącza umożliwiają użytkownikowi w łatwy sposób przeskakiwać do innych części dokumentu, otwierać inne dokumenty, a nawet przeskakiwać do dokumentów umieszczonych w Internecie. ' Tworzenie hiperłącza do zakładki w dokumencie ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:= ", _ SubAddress:="MyBookmark" ' Tworzenie hiperłącza do innego dokumentu ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:= _ "C:\MyDoc.doc", SubAddress:="" ' Tworzenie hiperłącza do dokumentu w Internecie ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:= _ "http://www.microsoft.com/office/", SubAddress:="" Tworzenie tabel Tabele zawierają informacje zorganizowane w wiersze i kolumny. Word pozwala na łatwe tworzenie nawet skomplikowanych tabel. ' Tworzenie tabeli ActiveDocument.Tables.Add Range:=Selection.Range, NumRows:=3, NumColumns:=3, Selection.Tables(1).AutoFormat, _ Format:=wdTableFormatClassic3, ApplyBorders:=True, _ ApplyShading:=True, ApplyFont:=True, ApplyColor:=True, _ ApplyHeadingRows:=True, ApplyLastRow:=False, _ ApplyFirstColumn:=True, ApplyLastColumn:=False, AutoFit:=False ' Wstawianie wierszy do tabeli Selection.InsertRows 1 ' Wstawianie kolumn do tabeli Selection.InsertColumns Ustawienia strony Okno dialogowe ustawień strony pozwala na ustawienie marginesów, rozmiaru papieru, orientacji, źródła papieru oraz układu. Wszystkie te ustawienia mogą być modyfikowane programowo. ' Ustawienie marginesów With ActiveDocument.PageSetup .TopMargin = InchesToPoints(0.5) .BottomMargin = InchesToPoints(0.5) .LeftMargin = InchesToPoints(0.5) .RightMargin = InchesToPoints(0.5) End With ' Ustawienie poziomej orientacji papieru. ActiveDocument.PageSetup.Orientation = wdOrientLandscape Podgląd wydruku Aby wywołać podgląd wydruku, należy użyć poniższej instrukcji. ' Podgląd wydruku ActiveDocument.PrintPreview Drukowanie dokumentów, kopert i etykiet Poniższy przykład przedstawia sposób, jak programowo wydrukować dokument, kopertę i etykietę: ' Drukowanie dokumentu Application.PrintOut FileName:="", Range:=wdPrintAllDocument, _ Item:= wdPrintDocumentContent, Copies:=1, Pages:="", _ PageType:=wdPrintAllPages, Collate:=True, Background:=True, PrintToFile:=False ' Drukownanie koperty ActiveDocument.Envelope.PrintOut ExtractAddress:=False, _ OmitReturnAddress :=False, PrintBarCode:=False, _ PrintFIMA:=False, Height:=InchesToPoints(4.13), _ Width:=InchesToPoints(9.5), Address:="Tom Howe", _ AutoText:= "ToolsCreateLabelsl", ReturnAddress:=_ "1001 SW Fifth Avenue, Suite 1100",ReturnAutoText:= _ "ToolsCreateLabels2", AddressFromLeft:=wdAutoPosition, _ AddressFromTop:=wdAutoPosition, ReturnAddressFromLeft:=_ wdAutoPosition, ReturnAddressFromTop:=wdAutoPosition ' Drukowanie etykiety Application.MailingLabel.DefaultPrintBarCode = False Application.MailingLabel.PrintOut Name:="2160 Mini", _ Address:="Tom Howe" Gdy codziennie drukowane są obszerne dokumenty i raporty, rozważ użycie procedury uruchamiającej drukowanie w nocy, gdy drukarki są wolne i ruch w sieci minimalny. Pola W Wordzie pola są używane do wstawiania do dokumentu różnych informacji, takich jak numery stron, daty i inne. Aby wstawić pole do dokumentu, wybierz Pole z menu Wstaw. W czasie pracy z dokumentem można przełączyć się pomiędzy tekstem i kodami pól przez naciśnięcie Alt+F9. Pola mogą być uaktualniane ręcznie przez naciśnięcie F9 lub automatycznie podczas drukowania dokumentu. Niektóre często używane pola zamieszczone są w tabeli 19.2. Tabela 19.2. Pola Worda Pole Worda Opis Ask Prosi użytkownika o wprowadzenie tekstu skojarzonego z zakładką CreateDate Data utworzenia dokumentu Fill-in Prosi użytkownika o wprowadzenie tekstu do wstawienia do dokumentu Tabela 19.2. Pola Worda (ciąg dalszy) Pole Worda Opis Hyperlink Otwiera i przeskakuje do pliku If Instrukcja warunkowa MergeField Wstawia pole korespondencji seryjnej Next Przejście do następnego rekordu korespondencji seryjnej SectionPages Wstawia ilość stron w sekcji W czasie pracy z polami przydatne są następujące skróty klawiszowe: Skrót klawiszowy Opis Alt+F9 Przełącza pomiędzy tekstem i kodami pól Ctrl+F9 Wstawia znak pola Ctrl+Shift+F9 Odłącza kody pól Delete Usuwa pole F9 Uaktualnia pola Informacje o dokumencie W czasie tworzenia i zapisywania dokumentu zapisywane są informacje pozwalające na późniejsze przeszukiwanie dokumentów. Na rysunku 19.9. znajdują się informacje zawarte w oknie dialogowym Właściwości. Rysunek 19.9. Informacje o dokumencie Worda W dokumencie zapisywane są następujące informacje: ? Nazwa dokumentu; ? Rozmiar dokumentu; ? Data i czas utworzenia; ? Data i czas ostatniej modyfikacji; ? Nazwa bazowego szablonu; ? Słowa kluczowe identyfikujące dokument; ? Miejsce zapisu dokumentu; ? Nazwisko autora; ? Nazwisko kierownika; ? Firma; ? Kategoria; ? Komentarz; ? Statystyka dokumentu; ? Informacje o zawartości. Można również utworzyć zestaw własnych właściwości bazujących na specyfice firmy. Popatrz na zakładkę Niestandardowe okna Właściwości. Inne możliwości Worda Word posiada wiele funkcji małej poligrafii. Są to m.in.: ? Układ wielokolumnowy; ? Możliwość importu grafiki z innych aplikacji; ? Wbudowywanie czcionek True Type; ? Krawędzie i cieniowanie; ? Word Art.; ? Wiele narzędzi rysunkowych. Automatyzacja Excela W tej części opisane są specyficzne dla Excela zagadnienia oraz przykłady automatyzacji. Model obiektów Excela Excel zawiera ponad 140 obiektów dostępnych poprzez VBA. Zajrzyj do „Obiekty Microsoft Excel” w pomocy do Excela. Zamieszczony jest tam diagram obiektów Excela. W tabeli 19.3 zestawione zostały często używane obiekty Excela. Obiekty, które mają także kolekcje zakończone są literą (s). Tabela 19.3. Obiekty Excela Obiekty Excela Description Application Cała aplikacja Excel Characters Znaki w obiekcie zawierającym znaki Chart(s) Wykresy w skoroszycie CubeField(s) Hierarchia lub pole wymiaru sześcianu OLAP DefaultWebOptions Ustawienia dla publikacji i zapisywania jako strony WWW Dialog(s) Wbudowane okna dialogowe DocumentProperty(s) Wbudowane i zdefiniowane właściwości dokumentu Name(s) Nazwa dla obszaru komórek PivotCache(s) Pamięć podręczna dla raportu z tabeli przestawnej PivotTable(s) Raport z tabeli przestawnej PublishObject(s) Obiekt w arkuszu, który będzie zapisywany na stronie WWW Range Komórka, wiersz, kolumna lub obszar komórek zawierający ciągły blok komórek lub trójwymiarowy obszar Shape(s) Rysunek lub panel do rysowania ShapeRange Podzbiór obiektów Style(s) Opis stylu dla obszaru WebOptions Ustawienia nadpisujące DefaultWebOptions Workbook(s) Otwarty arkusz dostępny przez numer lub nazwę Worksheet(s) Otwarty skoroszyt dostępny przez numer lub nazwę Przykłady automatyzacji Excela Przykłady poniższe przedstawiają automatyzację charakterystycznych właściwości i metod obiektów Excela. Formatowanie dokumentów Excela Excel posiada szerokie możliwości formatowania. Poniższe przykłady przedstawiają sposób w jaki należy formatować nagłówki kolumn danych i w jaki sposób wywoływać metodę AutoFit: ' Formatowanie nagłówków kolumn With objWorkSheet. ' Pogrubienie nagłówków kolumn .Cells(1, 1).Font.Bold = True .Cells(1, 2).Font.Bold = True End With ' Formatowanie danych w arkuszu With objWorkSheet.Columns With .Item(2) .NumberFormat = "0.00" .AutoFit End With ' Użycie metody AutoFit do formatowania danych .Item(1).AutoFit End With Tworzenie wykresów Użyj rejestratora makr, aby szybko utworzyć kod automatyzacji. Użyj kreatora wykresów do wybrania odpowiedniego wykresu. Poniższy przykład tworzy różne typy wykresów. ' Tworzenie wykresu kołowego objChart.ChartWizard Source:=objSheet.Cells(1, 1).CurrentRegion, _ Gallery:=xlPie, Format:=4, PlotBy:=xlColumns, _ CategoryLabels:=1, SeriesLabels:=1, HasLegend:=2, _ Title:="Sprzedaż (Wykres kołowy)" ' Tworzenie wykresu kolumnowego With ObjChart.ActiveChart .ChartType = xlColumnClustered .SetSourceData Source:=_ Sheets("5 najlepszych produktów").Range("Al:B6"), _ PlotBy:=xl0olumns End With ' Tworzenie wykresu pierścieniowego With ObjChart.ActiveChart .ChartType = xlDoughnut .SetSourceData Source:=_ Sheets("5 najlepszych produktów").Range("Al:B6"), _ PlotBy:=xlColumns .Location Where:=xlLocationAsNewSheet, Name:="Wykres pierścieniowy" .HasLegend = True .ChartTitle.Characters.Text = "Sprzedaż (wykres pierścieniowy" End With Program korzystający z automatyzacji może tworzyć w Excelu wykresy takie jak pokazany na rysunku 19.10. Użycie właściwości Parent Excel zawiera obiekt aplikacji oraz obiekt reprezentujący arkusz. Możesz dostać się do wszystkich obiektów Excela przez właściwości tych obiektów wysokiego poziomu. Generalnie, kod automatyzacji rozpoczyna pracę od tych obiektów i schodzi w dół hierarchii obiektów. W Excelu program może rozpocząć pracę od obiektu aplikacji, a następnie przenieść się do obiektu zeszytu i dalej do arkuszy i komórek. Gdy odwołujesz się do obiektu w hierarchii obiektów aplikacji, możesz przesuwać się w obu kierunkach. Rysunek 19.10. Tworzenie wykresów w Excelu Aby przesunąć się w górę hierarchii, używamy właściwości Parent. Przykładowo, gdy pracujesz z arkuszem, możesz odwołać się do zeszytu, który zawiera ten arkusz poprzez właściwość Parent. Fragment programu ilustrujący tę technikę zamieszczony jest poniżej. Private Sub ParentPropertyDemo() Dim objExcel As Excel.Application Dim objWorkBook as Excel.WorkBook ' Utworzenie obiektu Excela Set objExcel = New Excel.Application ' Otwarcie pliku Excela ' Upewnij się, że przykładowy plik znajduje się w podanym katalogu objExcel.Workbooks.Open _ ("C:\Automation\Sales by Country Data.xls") ' Ustaw zmienną objWork na aktywny zeszyt Set objWorkBook = objExcel.ActiveWorkBook ' Pobierz nazwę zeszytu z objWorkBook ("Sales by Country") MsgBox objWorkBook.Name ' Pobierz nazwę z obiektu aplikacji, używając właściwości Parent ' ("Microsoft Excel"). MsgBox objWorkBook.Parent.Name ' Maksymalizuj okno objExcel.WindowState = xlMaximized ' Pokaż Excela użytkownikowi objExcel.Visible = True ' Zakończ aplikację używając metody Quit 'objExcel.Quit ' Zwolnij obiekt aplikacji Set objExcel = Nothing End Sub W przykładzie tym otwierany jest zeszyt Excela. Poprzez właściwość Parent obiektu reprezentującego zeszyt odwołujemy się w górę hierarchii do obiektu aplikacji Excel. Automatyzacja PowerPoint W tej części opisane są specyficzne dla PowerPoint zagadnienia oraz przykłady automatyzacji. Model obiektów PowerPoint PowerPoint zawiera ponad 85 obiektów dostępnych poprzez VBA. Zajrzyj do „Obiekty Microsoft PowerPoint” w pomocy do PowerPoint. Zamieszczony jest tam diagram obiektów PowerPoint. W tabeli 19.4 zestawione zostały często używane obiekty PowerPoint. Obiekty, które mają także kolekcje, zakończone są literą (s). Tabela 19.4. Obiekty PowerPoint Obiekt PowerPoint Opis ActionSetting(s) Ustawienia opisujące sposób reakcji rysunków lub obszaru tekstu na manipulacje myszką w czasie pokazu Animationsetting(s) Ustawienia animacji rysunków w czasie pokazu Application Cała aplikacja PowerPoint Cell Komórka w tabeli CellRange Zbiór komórek we wierszu lub kolumnie tabeli ColorScheme(s) Schemat kolorów dla slajdu. Column(s) Kolumna tabeli DefaultWebOptions Ustawienia dla publikacji i zapisywania jako strony WWW DocumentWindow(s) Okno dokumentu Pane(s) Fragment okna dokumentów Presentation(s) Otwarta prezentacja dostępna przez numer lub nazwę Row(s) Wiersz tabeli Selection Zaznaczenie w dokumencie ShapeRange Zbiór kształtów w dokumencie SlideRange Zbiór slajdów SlideShowwindow(s) Okno, w którym odbywa się pokaz Table Tabela na slajdzie TextRange Tekst dołączony do kształtu WebOptions Ustawienia nadpisujące DefaultWebOptions Przykłady automatyzacji PowerPoint Poniższe przykłady przedstawiają przykłady użycia specyficznych właściwości i metod obiektów PowerPoint (rysunek 19.11) Dodanie slajdu Do dodania slajdu do prezentacji używana jest metoda Add. ' Dodaj slajd Set ppPres = objPP.Presentations.Add Rysunek 19.11. Prezentacja PowerPoint stworzona za pomocą automatyzacji Dodanie efektu przejścia Poniższy fragment programu dodaje do slajdu efekt przejścia: ' Dodanie do slajdu efektu przejścia objPresentation.Slides(5).SlideShowTransition.EntryEffect = _ ppEffectFade Wstawianie danych i formatowanie slajdów Program ten wstawia dane i formatuje slajd: With objPresentation.Slides(5).Shapes(1) .TextFrame.TextRange.Text = "Suma sprzedaży" .Shapes(1).TextFrame.TextRange.Characters.Font.Size = 80 End With With objPresentation.Shapes(2).TextFrame.TextRange .Text = Chr$(CharCode:=13) + "Spotkanie Rady Nadzorczej" _ + Chr$(CharCode:=13) + "Informacja o wartości sprzedaży" .Characters.Font.Color.RGB = RGB(0, 0, 255) .Characters.Font.Shadow = True End With With objPresentation.Shapes("Rectangle 3").TextFrame.TextRange, _ Characters(1, 53).Font .Size = 36 .Color.Scheme0olor = ppFill End With Wstawienie rysunku do slajdu Poniższy fragment dodaje do slajdu fotografię oraz formatuje slajd: Dim strFileName as String strFileName = ADOrs!Photos objPresentation.Shapes.AddPicture(FileName:=strFileName, _ LinkToFile:=msoFalse, SaveWithDocument:=msoTrue, _ Left:=110, Top:=260, Width:=250, Height:=250).Select Uruchamianie prezentacji Aby uruchomić prezentację, wykonaj: objPresentation.SlideShowSettings.Run Automatyzacja Outlook W tej części opisane są specyficzne dla Outlooka zagadnienia oraz przykłady automatyzacji. Model obiektów Outlook Outlook zawiera ponad 55 obiektów dostępnych poprzez VBA. Zajrzyj do „Obiekty Microsoft Outlook” w pomocy do Outlooka. Zamieszczony jest tam diagram obiektów Outlooka. W tabeli 19.5 zestawione zostały często używane obiekty Outlooka. Obiekty, które mają także kolekcje, zakończone są literą (s). Tabela 19.4. Obiekty Outlook Obiekt Outlook Opis Action(s) Specjalizowana czynność na obiekcie AddressEntries(s) Informacje o adresie przesyłki Application Cała aplikacja Outlook AppointmentItem Spotkanie w kalendarzu Tabela 19.4. Obiekty Outlook (ciąg dalszy) Obiekt Outlook Opis Attachment(s) Dołączony do przesyłki dokument ContactItem Pojedynczy kontakt w folderze Kontakty DistListItem Lista wysyłkowa w folderze Kontakty DocumentItem Dokument w folderze Outlook Explorer(s) Okno wyświetlające zawartość foldera Folders Kolekcja obiektów MAPIFolder Inspector(s) Okno wyświetlające element Outlook Items Kolekcja elementów w MAPIFolder JournalItem Pozycja w folderze dziennika NameSpace Główny obiekt umożliwiający dostęp do danych NoteItem Notatka w folderze notatek Pages Kolekcja stron PostItem List w folderze publicznym PropertyPage(s) Strona właściwości definiowanych przez użytkownika Recipient(s) Użytkownik lub zasób SyncObject(s) Profil synchronizacji dla użytkownika TaskItem Zadanie w folderze zadań Przykłady automatyzacji Outlook Poniższe przykłady przedstawiają przykłady użycia specyficznych właściwości i metod obiektów Outlooka. Dodawanie i wyświetlanie folderów Fragment programu, który dodaje folder oraz wyświetla folder Public. ' Dodaj folder do domyślnego foldery kalendarza Set objSubFolder = objOutlook.GetNamespace("MAPI").GetDefaultFolder_ (olFolderCalendar).Folders.Add("New Calendar") Dodawanie nowego zadania i wyświetlenie zadań Poniższy kod dodaje nowe zadanie i wyświetla zadania: Dim objOutlook As Outlook.Application Dim objTaskFolder As Object Dim objTaskItem As Object Set objTaskItem = objOutlook.CreateItem(olTaskItem) With objTaskItem .Subject = "To jest temat zadania" .Body = "To jest treść zadania" ' Możesz także dodać przypominanie, czas i datę .Save End With ' Przejście do foldera zadań Set objTaskFolder = obj0utlook.GetNamespace("MAPI")._ GetDefaultFolder(13) ' Wyświetlenie zawartości foldera zadań objTaskFolder.Display Tworzenie wiadomości e-mail z załącznikiem W łatwy sposób możesz wysłać wiadomość e-mail z aplikacji Accessa, automatyzując Outlooka (rysunek 19.12). Rysunek 19.12. Wysłanie wiadomości e-mail z załącznikiem z Accessa Program ten tworzy nową wiadomość e-mail i załącza arkusz Excela: Dim objOutlook As Outlook.Application Dim objRecipient As Recipient Dim objAttachment As Attachment Dim objMailItem As MailItem ' Tworzenie przesyłki e-mail Set objMailltem = obj0utlook.CreateItem(olMailItem) With objMailItem ' Tworzenie odbiorcy przesyłki Set objRecipient = .Recipients.Add("Steven Johnson") objRecipient.Type = olTo ' Ustawienie tematu, treści i ważności przesyłki .Subject = "To jest mój raport sprzedaży do oceny" .Body = "Jeżeli potrzebujesz innych informacji, _ proszę o kontakt." & vbOrLf & vbCrLf .Importance = olImportanceHigh ' Dołączenie arkusza i wykresu w pliku Excela: "Sales by Country." Set objAttachment = .Attachments.Add_ ("C:\Automation\Sales by Country.xls") ' rozwinięcie nazw odbiorców For Each objRecipient In .Recipients objRecipient.Resolve Next ' Wyświetlenie wiadomości .Display ' Wysłanie wiadomości .Send End With Tworzenie elementów Outlooka Poniższe instrukcje tworzą różne elementy Outlooka. Element Outlook Instrukcja tworząca element Spotkanie Set objItem = objOutlook.CreateItem(olAppointmentItem) Kontakt Set objItem = objOutlook.CreateItem(olContactItem) Dziennik Set objItem = objOutlook.CreateItem(olJournalItem) Wiadomość e-mail Set objItem = objOutlook.CreateItem(olMailItem) Notatka Set objItem = objOutlook.CreateItem(olNoteItem) Wyświetlanie domyślnych folderów W tabeli 19.6 zamieszczone są stałe używane w metodzie GetDefaultFolder do wyświetlenia domyślnych folderów Outlooka. Tabela 19.6. Stałe folderów Nazwa foldera Stała dla metody GetDefaultFolder Kalendarz GetDefaultFolder(olFolderCalendar) Kontakty GetDefaultFolder(olFolderContacts) Skrzynka odbiorcza GetDefaultFolder(olFolderInbox) Dziennik GetDefaultFolder(olFolderJournal) Notatki GetDefaultFolder(olFolderNotes) Zadania GetDefaultFolder(olFolderTasks) Wyświetlenie foldera publicznego Poniższy fragment programu wyświetla publiczny folder programu Outlook. Dim objOutlook As Outlook.Application Dim objNameSpace As Outlook.NameSpace Dim objPublicFolders As Outlook.Folders Dim objAllPublicFolders As Object Dim objOffice0ontacts As Object Set objNameSpace = obj0utlook.GetNamespace("MAPI") Set objPublicFolders = objNameSpace.Folders("Public Folders") Set objAllPublicFolders = objPublicFolders.Folders("Favorites") Set objOffiEeContacts = objAllPublicFolders.Folders("Office Contacts") ' Wyświetlenie publicznego foldera "Office Contacts." objOfficeContacts.DisplayThe Szukanie elementu w Outlooku Kod ten pokazuje jak znaleźć kontakt w Outlooku. Set objItem = objContactItems.Find("[File As] = 'Zelko, John'") objItem.Display Filtrowanie elementów w Outlooku Do filtrowania elementów Outlooka używana jest metoda Restrict. Poniższy program zwraca tylko te kontakty, które mają imię „Steve”: Set objFilter = objContactItems.Restrict("[First Name] = 'Steve' ") W przykładach do tego rozdziału znajduje się kompletny program do internetowej poczty elektronicznej. Przesyłki mogą być wysyłane z Outlooka do grup odbiorców zapisanych w bazie danych Accessa. W przykładach znajdują się także program przesyłający listy z Worda do odbiorców z kontaktów Outlooka. Automatyzacja Graph W tej części opisane są specyficzne dla Graph zagadnienia oraz przykłady automatyzacji. Model obiektów Graph Graph zawiera ponad 10 obiektów dostępnych poprzez VBA. Tabela 19.7 zawiera często używane obiekty. Obiekty, które mają także kolekcje, zakończone są literą (s). Tabela 19.7. Obiekty Graph Obiekt Graph Opis Application Cała aplikacja Microsoft Graph AutoCorrect Funkcja autokorekty w Graph Axis(s) Oś Chart Wykres Tabela 19.7. Obiekty Graph (ciąg dalszy) Obiekt Graph Opis ChartArea Obszar wykresu ChartGroup(s) Jedna lub więcej serii punktów narysowanych na wykresie Datasheet Arkusz danych DataTable Tabela danych w wykresie Legend Legenda na wykresie PlotArea Obszar rysowania w wykresie Series(s) Serie danych w wykresie Tworzenie wykresu Skomplikowane dokumenty często zawierają wykresy i diagramy. Word i inne produkty Office używają Microsoft Graph do tworzenia i formatowania wykresów. W Accessie jest bardzo łatwo utworzyć wykres na formularzu, używając kreatora. Często jednak możesz chcieć pokazać różne typy wykresów dla różnych danych. Zamiast tworzyć sześć formularzy z różnymi wykresami, możesz manipulować wykresem na formularzu za pomocą automatyzacji, aby pozwolić użytkownikowi na obejrzenie różnych prezentacji graficznych jego danych (rysunek 19.13). Rysunek 19.13. Pojedynczy formularz może pokazywać różne typy wykresów Przykłady automatyzacji Graph Po utworzeniu formularza z wykresem użyj obiektu Chart i zmień właściwość ChartType, aby uzyskać różne typy wykresu. Przykładowo, aby zmienić wykres kolumnowy na kołowy, użyj następującego programu: ' Przypisanie zmiennej do wykresu na ekranie Set objChart = Me.objProductsSold.Object ' Zmień typ wykresu na kołowy objChart.ChartType = xl3DPie ' Pokaż legendę objChart.HasLegend = True ' Usuń zmienną obiektową Set objChart = Nothing Poprzez proste użycie właściwości i metod Microsoft Graph, możesz formatować i zmieniać wykres w zależności od potrzeb: dodawać legendę, wskaźniki danych, etykietki, wzory tła itp. Gdy automatyzujesz aplikację ze względu na jej możliwości rysowania wykresów, możesz użyć Microsoft Excel lub Microsoft Graph. Powinieneś użyć Excela, ze względu na bardziej rozwinięty model obiektów. Automatyzacja MapPoint W tej części opisane są specyficzne dla MapPoint zagadnienia oraz przykłady automatyzacji. Model obiektów MapPoint Obiekty MapPoint są dostępne poprzez VBA. Zajrzyj do „Obiekty Microsoft MapPoint” w pomocy do MapPoint. Zamieszczony jest tam diagram obiektów MapPoint. W tabeli 19.8 zestawione zostały często używane obiekty MapPoint. Tabela 19.8. Obiekty MapPoint Obiekty MapPoint Opis AppLication Cała aplikacja MapPoint Location Lokalizacja Map Mapa PushPin Pineska Przykłady automatyzacji MapPoint Poniższy przykład automatyzacji MapPoint ma na celu wyświetlenia odpowiedniej mapy (popatrz na rysunek 19.14). Może być on użyty do otwarcia mapy i pokazania położenia klienta. ' Ustaw odwołanie do MapPoint 1.0 Dim objMapPoint As MapPoint.Application Dim objMap As MapPoint.Map Set objMapPoint = New MapPoint.Application ' Otwórz mapę Portland w Oregonie Set objMap = objMapPoint.OpenMap("C:\Maps\Portland, OR.ptm") ' Zwolnienie zmiennej obiektowej Set objMap = Nothing Set objMapPoint = Nothing Rysunek 19.14. Pokazanie mapy w aplikacji Accessa przy użyciu MapPoint Automatyzacja FrontPage W tej części opisane są specyficzne dla FrontPage zagadnienia oraz przykłady automatyzacji. Model obiektów FrontPage Obiekty FrontPage są dostępne poprzez VBA. Zajrzyj do „Obiekty Microsoft FrontPage” w pomocy do FrontPage. Zamieszczony jest tam diagram obiektów FrontPage. W tabeli 19.9 zestawione zostały często używane obiekty FrontPage. Tabela 19.9. Obiekty FrontPage Obiekt FrontPage Opis Application Cała aplikacja FrontPage HomeNavigationNode Węzeł nawigacji dla strony domowej Theme(s) Temat Web(s) Sieć FrontPage WebFile(s) Plik w opartej na FrontPage sieci WebFolder(s) Folder w opartej na FrontPage sieci WebWindow(s) Otwarte okno w opartej na FrontPage sieci Przykłady automatyzacji FrontPage Automatyzując FrontPage, możesz m.in.: ? Utworzyć nową sieć lub otworzyć już istniejącą; ? Tworzyć lub otwierać foldery sieci; ? Tworzyć, otwierać i modyfikować pliki w sieci; ? Stosować schematy. Przykład poniższy automatyzuje FrontPage, aby utworzyć nową sieć, wstawić do niej nową stronę, wstawić dane Accessa na stronę i zastosować schemat. ' Ustaw odwołania do ADO 2.1 oraz FrontPage 4.0 Web Objects. Dim objFrontPage As FrontPage.WebWindow Dim objWeb As Web Dim objWebFile As WebFile Dim objWebWindow As WebWindow Dim strSQL As String Dim ADOrs As ADODB.Recordset Dim Conn As ADODB.Connection Set objFrontPage = New FrontPage.WebWindow Set objWeb = Webs.Open("C:\Automation\Web") Set objWebFile = ActiveWeb.RootFolder.Files.Add _ ("Podsumowanie sprzedazy.htm") ' Tworzenie połączenia ADO Set Conn = New ADODB.Connection ' Tworzenie recordsetu ADO Set ADOrs = New ADODB.Recordset With Conn .Provider = "Microsoft.JET.OLEDB.3.51" .Open "C:\Automation\Automation.mdb" End With strSQL = "SELECT Categories.CategoryName AS Category, Sum([Order Details].UnitPrice) AS Price FROM _ (Categories INNER JOIN Products ON Categories CategoryID = _ Products.CategoryID) INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID _ GROUP BY Categories.CategoryName _ HAVING (((Sum([Order Details].UnitPrice))>0));" ' Otwarcie recordsetu ADO ADOrs.Open strSOL, Conn Set objWebWindow = Webs(0).WebWindows(0) objWebWindow.Visible = True ' Aktywacja okna sieci objWebWindow.Activate ' Otwórz stronę sieci objWebFile.Open ' Wstaw nagłówek objFrontPage.ActiveDocument.Body.insertAdjacentText "BeforeEnd", _ "Suma sprzedaży kategorii" ' Wstaw dane z bazy danych Do Until ADOrs.EOF objFrontPage.ActiveDocument.Body.insertRdjacentText _ "BeforeEnd", ADOrs!Category.Value & vbTab & vbTab &_ ADOrs!Price.Value ADOrs.MoveNext Loop ' Zmień schemat strony na "artsy" objWebWindow.ActivePageWindow.ApplyTheme "artsy", _ fpThemePropertiesAll ' Zapisz stronę objWebWindow.ActivePageWindow.Save ' Zamknij recordset. ADOrs.Close ' Wyłącz klepsydrę Screen.MousePointer = 0 ' Zwolnij zmienne obiektowe Set ADOrs = Nothing Set objWeb = Nothing Set objWebFile = Nothing Set objWebWindow = Nothing Set objFrontPage = Nothing Automatyzacja Bindera W tej części opisane są specyficzne dla Bindera zagadnienia oraz przykłady automatyzacji. Model obiektów Bindera Obiekty Bindera są dostępne poprzez VBA. Zajrzyj do pomocy Bindera. Zamieszczony jest tam diagram obiektów Bindera. W tabeli 19.10 zestawione zostały często używane obiekty Bindera. Tabela 19.10. Obiekty Bindera Obiekt Bindera Opis Binder Aplikacja Microsoft Office Binder DocumentProperty(s) Wbudowana lub zdefiniowana właściwość dokumentu PageSetup Atrybuty ustawień strony Section(s) Sekcja w Binderze Przykłady automatyzacji Bindera Zamieszczony tutaj kod tworzy nowy spinacz i dodaje do niego dokumenty: Dim objBinder As Binder Set objBinder = New Binder With objBinder ' Dodaj dokument Worda do bindera .Sections.Add FileName:="C:\Automation\Northwind Magazine Ad.doc" .Sections(1).Name = "Ogłoszenie Northwind Magazine" ' Dodaj arkusz Excela do bindera .Sections.Add FileName:="C:\Automation\Sales by Country Data.xls" .Sections(1).Name = "Arkusz automatyzacji" ' Dodaj prezentację PowrePoint do bindera .Sections.Add FileName:="C:\Automation\Board Of Director _ Meeting.ppt" .Sections(1).Name = "Prezentacja na spotkanie Rady Nadzorczej" End With objBinder.Visible = True ' Zapisz binder ' objBinder.SaveAs "Automation.odb" Set objBinder = Nothing Program ten przy użyciu automatyzacji tworzy nowy binder z różnymi dokumentami Office (patrz rysunek 19.15). Rysunek 19.15. Automatyzacja Microsoft Binder Zabezpieczanie dokumentów, szablonów i kodu programu Dokumenty, formularze, szablony i moduły kodu mogą być zabezpieczone hasłem. Aby je zabezpieczyć, przejdź do okna projektu w edytorze Visual Basic. Aby zabezpieczyć cały projekt, wywołaj właściwości projektu. Kliknij zakładkę Protection i wprowadź hasło. W ten sam sposób można zabezpieczać hasłem formularze, szablony, dokumenty i moduły kodu. Rozdział 20. Użycie Visual Basic z Accessem W tym rozdziale: ? Tworzenie komponentów ActiveX. ? Tworzenie formantów ActiveX. Access jest potężnym narzędziem programistycznym, ale jednak nie potrafi wszystkiego. Visual Basic to wspaniałe uzupełnienie Accessa. Przy użyciu VB można tworzyć samodzielne komponenty ActiveX oraz formanty ActiveX. W rozdziale tym zakładamy, że nie masz żadnego doświadczenia w programowaniu w Visual Basicu. Korzystając z opisu, krok po kroku nauczysz się tworzenia formantów ActiveX, które będziesz mógł wykorzystać w swoich aplikacjach w Accessie. Opiszemy także krok po kroku, jak tworzy się komponenty w Visual Basicu, które mogą być wykorzystane w Accessie, Visual Basicu i innych aplikacjach Office. Aby prześledzić przykłady zawarte w tym rozdziale, powinieneś mieć dowolną wersję Visual Basic 6. Jeżeli nie masz Visual Basica, najtańszą wersją jest Learning Edition. Możesz zapytać, „Jaka jest różnica pomiędzy Visual Basic i Visual Basic for Appliccations (VBA)?” VBA jest językiem programowania użytym w Visual Basicu, Accessie i innych aplikacjach Office. VBA w Office 2000 oraz Visual Basic 6 są dokładnie takie same. Jednak Visual Basic 6 jest samodzielnym środowiskiem programistycznym, które będziesz używać w tym rozdziale do tworzenia formantów ActiveX. Tworzenie komponentów ActiveX Za pomocą Visual Basica możesz tworzyć komponenty ActiveX i używać ich w aplikacjach Accessa. Przykładowym komponentem, który utworzymy w tym rozdziale, będzie komponent umożliwiający odgrywanie plików dźwiękowych w aplikacjach Accessa. Komponenty ActiveX oraz kontrolki ActiveX omówione w tym rozdziale zawarte są na płycie CD-ROM dołączonej do książki. Komponenty te muszą zostać zarejestrowane w systemie. Aby to zrobić, otwórz plik projektu i skompiluj go. W dalszej części rozdziału znajdziesz dodatkowe informacje na temat rejestrowania komponentów. Czym są komponenty ActiveX Komponent ActiveX to kod w module klasowym skompilowany do postaci pliku wykonywalnego (EXE) lub biblioteki dynamicznej (DLL). Korzyścią tworzenia komponentów ActiveX jest to, że można go stosować w każdej aplikacji wspierającej COM. Dlatego, zamiast ograniczać się tylko do pojedynczej aplikacji Accessa, komponent może być użyty w wielu aplikacjach Accessa, Visual Basica, Office i innych. W rozdziale 11. „Tworzenie obiektów w modułach klasowych” tworzyłeś obiekt dźwiękowy przy użyciu modułu klasowego cSound. W module klasowym plik dźwiękowy jest przekazywany do wywołania Windows API, aby odegrać dźwięk. Kod w module klasowym zamieszczony jest na wydruku 20.1. Wydruk 20.1. Moduł klasowy cSound Option Explicit ' Wywołanie Windows API Private Declare Function sndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal lpszSoundName As String, ByVal uFlags As Long) As Long Public Sub PlaySound(SoundFile As String) ' Odegraj plik dźwiękowy sndPlaySound SoundFile, 1 End Sub Problem z modułem klasowym polega na tym, że może być użyty tylko w aplikacji Accessa, w której istnieje ten moduł. Jeżeli tworzymy nową aplikację, moduł musi zostać do niej zaimportowany. Jednak, jeżeli zmienisz w przyszłości kod modułu, będziesz musiał wprowadzić ręcznie te poprawki w każdej aplikacji używającej tego modułu. Poprzez utworzenie komponentu ActiveX dla obiektu dźwiękowego wszystkie aplikacje Accessa (jak również inne aplikacje) mogą użyć komponentu ActiveX. Jeżeli musisz wprowadzić zmiany, wprowadzone zostaną w jednym miejscu. Różnice między ActiveX EXE i ActiveX DLL Gdy tworzysz komponent ActiveX w Visual Basicu, możesz utworzyć ActiveX EXE albo ActiveX DLL. Jaka jest różnica? Komponent ActiveX w postaci pliku EXE posiada własną przestrzeń procesu oddzielną od wywołującej go aplikacji. Wywołania z aplikacji są przesyłane pomiędzy procesami do komponentu. Jest to wolniejsze niż gdyby komponent ActiveX był wykonywany w tym samym procesie. Zaletą ActiveX w postaci EXE jest to, że jeżeli załamie się, wywołująca go aplikacja może dalej działać. Komponent w postaci biblioteki DLL wykonywany jest w tej samej przestrzeni procesu co wywołująca go aplikacja. Ponieważ nie zachodzi komunikacja międzyprocesowa, szybkość wykonania jest wyraźnie większa. Jeżeli jednak komponent spowoduje błąd, zostanie zatrzymana cała aplikacja. Najczęściej jednak będziesz korzystać z komponentów w bibliotekach dynamicznych. ActiveX DLL jest wykonywany przez ten sam proces, co wywołująca go aplikacja Accessa. Dlatego ActiveX DLL jest wyraźnie szybszy niż ActiveX EXE. Tworzenie komponentu ActiveX Aby utworzyć komponent ActiveX odgrywający dźwięki, uruchom Visual Basic. W oknie dialogowym New Project, pokazanym na rysunku 20.1, wybierz ActiveX DLL. Rysunek 20.1. Wybór ActiveX DLL w oknie New Project Gdy projekt zostanie otwarty w IDE, zauważysz jeden moduł klasowy nazywany Class1. W oknie Project Properties zmień nazwę modułu na cSound. Otwórz w Accessie aplikację z rozdziału 11. „Tworzenie obiektów z modułów klas.mdb”. Otwórz moduł cSound i w trybie projektowania skopiuj jego zawartość do schowka. Wróć do projektu w Visual Basicu i wklej całą zawartość do okna kodu modułu cSound w sposób pokazany na rysunku 20.2. Rysunek 20.2. Kopia cSound w oknie modułu klasowego W oknie Project Properties można znaleźć właściwość Instancing. Jej domyślną wartością jest MultiUse. Ponieważ komponenty ActiveX zawierają moduły klasowe, można tworzyć wiele egzemplarzy danej klasy. Dzięki temu pojedynczy moduł kodu może być użyty wiele razy. Jeżeli właściwość Instancing jest ustawiona na MultiUse, aplikacja Accessa może tworzyć obiekty dźwiękowe przy użyciu tego komponentu. Jeżeli programy będą kilkakrotnie żądały utworzenia obiektu, zostanie utworzony tylko jeden. Zmniejsza to zużycie pamięci, ale jeżeli wystąpi drugie żądanie dostępu do obiektu, program zostanie wstrzymany aż do zakończenia obsługi wcześniejszego żądania. Najczęściej używana jest domyślna wartość MultiUse. Istnieje sześć ustawień właściwości Instancing. Ponieważ w tym rozdziale skupimy się na programowaniu dla potrzeb Accessa, nie będą one szczegółowo opisane. Dodatkowe informacje znajdują się w pomocy do Visual Basica. Następnym krokiem jest modyfikacja właściwości projektu. Wybierz Project1 Properties z menu Project. Na zakładce General w oknie Project Properties (rysunek 20.3) wprowadź nazwę projektu cSoundObject (nazwa projektu nie może zawierać spacji). W polu Project Description wprowadź opis projektu np.: Obiekt cSound. W polu tym mogą występować spacje i jest to nazwa, która pojawi się w oknie References podczas ustawiania odwołania do komponentu. Na zakładce Make w oknie właściwości projektu, która pokazana jest na rysunku 20.4, można podać numer wersji. Dobrze jest zaznaczyć pole wyboru Auto Increment, co spowoduje, że za każdą kompilacją komponentu zostanie wprowadzony nowy numer wersji. Rysunek 20.3. Zakładka General okna właściwości projektu Rysunek 20.4. Zakładka Make właściwości projektu W części Version Information można wprowadzić nazwę, informacje o prawach autorskich, nazwę produktu i inne informacje. Pozostałe ustawienia nie muszą być zmieniane w tym przykładzie. Na zakładce Compile, która jest pokazana na rysunku 20.5, domyślnym ustawieniem jest Compile to Native Code. Zwykle nie będziesz musiał zmieniać tego ustawienia. Jeżeli zmienisz na Compile to P-Code, program będzie wolniejszy, ale komponent będzie mniejszy. Szczegółowy opis ustawień na zakładce Compile znajduje się w pomocy Visual Basica. Rysunek 20.5. Zakładka Compile właściwości projektu Na zakładce Component, która pokazana jest na rysunku 20.6, domyślnym ustawieniem jest Project Compatibility. Takiego ustawienia powinieneś używać przy tworzeniu komponentów. Inne ustawienia, No Compatibility oraz Binary Compatibility, omówione zostaną później w części „Dystrybucja komponentów ActiveX”. Rysunek 20.6. Zakładka Component właściwości projektu W tym przykładzie nie będziemy zmieniać ustawień z zakładki Debugging. Kliknij przycisk OK, aby zamknąć okno właściwości obiektu. Aby zapisać projekt i wszystkie moduły klasowe, wybierz Save Project z menu File. Najlepiej zapisywać projekt (plik .vbp) oraz moduł klasy (plik .cls) w tym samym katalogu (np. Obiekt Sound). Kompilowanie biblioteki DLL Po utworzeniu i zapisaniu projektu może zostać skompilowana biblioteka DLL zawierająca obiekt. Jest to bardzo łatwe. Wybierz Make cSound Object DLL z menu File. Prawdopodobnie VB zaproponuje zapis pliku DLL w katalogu Visual Basica. Zapisz plik DLL z obiektem cSound w tym samym katalogu co plik projektu. Zapis pliku DLL w jednym katalogu razem z plikiem projektu ułatwia późniejsze odszukanie plików. Biblioteka DLL została utworzona i zarejestrowana w systemie. W Visual Basicu, gdy kompilujesz plik DLL, możesz od razu rozpocząć korzysta z niego. W dalszej części rozdziału opisujemy, w jaki sposób rozprowadzać pliki DLL do innych użytkowników. Jeżeli zajrzysz do katalogu z zapisanym projektem (rysunek 20.7), zauważysz wiele plików. Visual Basic zapisuje formularze, moduły i inne obiekty w oddzielnych plikach. Inaczej postępuje Access, który umieszcza wszystkie obiekty w jednym pliku MDB. Rysunek 20.7. Visual Basic zapisuje obiekty w oddzielnych plikach Przykład ten przedstawia sposób, jak utworzyć ActiveX DLL. Podobnie tworzy się ActiveX EXE. Rozpocznij po prostu od wybrania ActiveX EXE w oknie New Project. Użycie komponentu ActiveX cSound Po utworzeniu komponentu możesz użyć go w aplikacji Accessa. Aplikacja Accessa musi ustawić odwołanie do komponentu, utworzyć egzemplarz obiektu i użyć go. Poniżej przedstawimy sposób użycia komponentu. Utwórz pustą bazę Accessa o nazwie np.: Sound i zapisz ją. Następnie utwórz pusty formularz i umieść na nim przycisk do testowania komponentu. Utwórz procedurę obsługi zdarzenia Click przycisku. W oknie modułu ustaw odwołanie do komponentu ActiveX cSound. Uruchom okno References z menu Tools i zaznacz pole wyboru obok Obiekt cSound. Obiekt cSound to nazwa wprowadzona wcześniej w polu Description w oknie właściwości projektu. Zamknij okno References przez kliknięcie przycisku OK. Ustawienie odwołania do obiektu cSound jest niezbędne, ponieważ jest to komponent oddzielny od aplikacji Accessa. Zauważ, że używasz obiektu cSound bez tworzenia żadnego modułu w aplikacji Accessa. Jako obsługę zdarzenia Click wpisz następującą procedurę: Private Sub cmdSound_Click() Dim objSound As cSound Set objSound = New cSound ' Jeżeli używasz Windows NT, użyj ścieżki "C:\WINNT" objSound.PlaySound "C:\Windows\Media\chimes.wav" Set objSound = Nothing End Sub Czy zauważyłeś w trakcie wpisywania tekstu programu działanie IntelliSense dla Twojego obiektu (rysunek 20.8)? Jest to wspaniała pomoc ułatwiająca i przyspieszająca wpisywanie kodu programu. Rysunek 20.8. IntelliSense działające dla obiektu cSound Przy użyciu kilku wierszy kodu można pokazać, jak łatwo utworzyć obiekt dźwiękowy z komponentu ActiveX i używać jego właściwości, metod i zdarzeń. Możesz także używać komponentu cSound w innych aplikacjach Accessa. Zmiany będą ułatwione, ponieważ wszystkie aplikacje Accessa i inne używają tego samego komponentu. Jeżeli zdecydujesz się dodać lub zmienić właściwość, metodę lub zdarzenie w komponencie, zrobisz to tylko w jednym miejscu, w samym komponencie. Użycie komponentu w innych aplikacjach Oprócz Accessa możesz używać komponentu cSound w innych aplikacjach wspierających COM. Możesz użyć tego komponentu w VB, Office, Outlook i programowaniu dla WWW. Dystrybucja komponentów ActiveX W trakcie dystrybucji komponentów do użytkowników musisz zająć się następującymi zagadnieniami: ? Instalowanie komponentu; ? Ustawienia rejestru komponentu; ? Zgodność komponentów. Instalowanie komponentu Najprostszą metodą instalacji komponentu na komputerze użytkownika jest użycie kreatora Package and Deployment Wizard dostarczanego razem z Visual Basicem. Kreator ten tworzy program instalacyjny, który instaluje komponent i wprowadza niezbędne wpisy do rejestru. Dostępne są także podobne programy innych firm. Tworzenie programu instalacyjnego przy użyciu Package and Deployment Wizard Po uruchomieniu kreatora na jego pierwszej stronie znajduje się przycisk Browse. Po kliknięciu tego przycisku należy odnaleźć plik projektu (np.: cSoundObject.vbp, tak jak na rysunku 20.9). Rysunek 20.9. Pierwszy ekran kreatora Package and Deployment Na następnej stronie kreatora należy wybrać rodzaj skryptu pakowania (Packaging Script). W tym przykładzie wybierz None (rysunek 20.10). Rysunek 20.10. Wybór skryptu pakowania Na kolejnej stronie kreatora należy podać typ pakietu (rysunek 20.11). Dostępne są trzy typy pakietów: ? Standardowy program instalacyjny (Standard Setup Package): tworzy zwykły program instalacyjny. ? Instalacja internetowa: tworzy program instalacji przez Internet. ? Pliki zależne: program instalacyjny zawiera tylko pliki zależne. W tym przykładzie użyjemy standardowego pakietu instalacyjnego. Na kolejnym ekranie podajemy katalog, w którym umieszczone zostaną pliki instalacyjne (rysunek 20.12). Jeżeli docelowy katalog nie istnieje, zostanie automatycznie utworzony. Rysunek 20.11. Wybór typu pakietu instalacyjnego Rysunek 20.12. Wybór katalogu na pakiet instalacyjny Następny ekran zawiera listę plików, które zostaną umieszczone w pakiecie (rysunek 20.13). Kreator ten automatycznie umieszcza na liście wszystkie potrzebne pliki. Zauważ, że na liście oprócz samego komponentu znajdują się również biblioteki Visual Basica i inne pliki. Jeżeli chcesz dodać jeszcze inne pliki do pakietu, kliknij przycisk Add. Rysunek 20.13. Lista plików w programie instalacyjnym Biblioteki Visual Basica muszą być zainstalowane na komputerze użytkownika. Po jednokrotnym zainstalowaniu tych plików możesz nie umieszczać ich już w programie instalacyjnym, co wyraźnie zmniejsza jego objętość. Na następnym ekranie ustawiamy parametry plików CAB. Pojedynczy plik CAB (plik jest skompresowany) może być umieszczony na dysku CD-ROM lub w sieci, natomiast dla dyskietek należy utworzyć zwykle kilka plików. Rysunek 20.14. Ustawianie parametrów plików CAB Na kolejnej stronie kreatora podajemy tytuł programu instalacyjnego (rysunek 20.15). Dobrze jest wpisać czytelną nazwę programu, ponieważ właśnie ten napis zobaczy użytkownik po uruchomieniu programu instalacyjnego. Rysunek 20.15. Wpisywanie tytułu instalacji Na następnym ekranie wybieramy elementy, które umieszczone zostaną w menu Start (rysunek 20.16). Możesz utworzyć grupę programów, w której będzie znajdowała się ikona instalowanego programu. Ponieważ zajmujemy się komponentem, nie będzie potrzebna żadna grupa. Rysunek 20.16. Definiowanie elementów menu Start Na kolejnym ekranie podajemy katalog, do którego będzie zainstalowany nasz komponent (rysunek 20.17). Zamiast instalować komponent do katalogu Windows\System, umieść go w katalogu aplikacji, co ułatwi utrzymanie porządku. Rysunek 20.17. Definiowanie katalogu docelowego Na następnym ekranie zaznaczamy, czy nasz komponent będzie zainstalowany jako plik współdzielony, czy nie (rysunek 20.18). Plik współdzielony to taki, który jest używany przez więcej niż jedną aplikację. Rysunek 20.18. Definiowanie plików współdzielonych Na ostatniej stronie kreatora podajemy nazwę skryptu pakowania, który przechowuje wszystkie ustawione przed chwilą ustawienia do późniejszego odtworzenia. Kliknij przycisk Finish, aby utworzyć pakiet. Rysunek 20.19. Wpisywanie nazwy skryptu i tworzenie pakietu Po utworzeniu pliku (lub plików) CAB zostanie również utworzony raport z utworzenia pakietu zawierający dodatkowe informacje. Jeżeli chcesz, możesz go zapisać do pliku. Wszystkie pliki instalacyjne znajdują się teraz w katalogu, który podałeś w trakcie pracy kreatora (rysunek 20.20). Pliki te należy rozesłać do klientów, którzy zainstalują komponent na swoich komputerach tak jak wszystkie inne programy. Dwukrotne kliknięcie ikony programu instalacyjnego (lub poprzez funkcję Dodaj/Usuń Programy w Panelu Sterowania) uruchomi program instalacyjny, który zainstaluje komponent i inne potrzebne pliki (rysunek 20.21). Rysunek 20.20. Utworzone pliki instalacyjne Rysunek 20.21. Uruchomiony program instalacyjny Rozprowadzanie plików przy użyciu kreatora Package and Deployment Wizard Po utworzeniu plików instalacji musisz rozprowadzić je do użytkowników. Część Deploy kreatora Package and Deployment Wizard zawiera procedurę ułatwiającą ten proces. Uruchom kreator i na pierwszym ekranie kliknij przycisk Browse, aby odszukać plik projektu (np. cSoundObject.vbp, tak jak na rysunku 20.22). Następnie kliknij przycisk Deploy. Rysunek 20.22. Kliknij przycisk Deploy Na następnym ekranie wybierz skrypt dystrybucji (rysunek 20.23). Rysunek 20.23. Wybór skryptu dystrybucji Na kolejnym ekranie wybierz pakiet, który chcesz rozprowadzać (rysunek 20.24). Rysunek 20.24. Wybór pakietu do dystrybucji Następny ekran zawiera listę dostępnych metod dystrybucji. Można umieścić pakiet w lokalnym lub sieciowym katalogu albo wysłać na serwer WWW (rysunek 20.25). W tym przykładzie użyjemy katalogu na dysku. Na kolejnym ekranie kreatora wybieramy katalog, do którego będą wysyłane pliki pakietu (rysunek 20.26). Może być to katalog na serwerze sieciowym. Rysunek 20.25. Wybór metody dystrybucji Rysunek 20.26. Wybór katalogu docelowego Na ostatnim ekranie można podać nazwę skryptu, do którego zostaną zapisane ustawienia (rysunek 20.27). Można go użyć przy kolejnym użyciu tego kreatora. Aby zakończyć pracę kreatora i umieścić pliki w katalogu dystrybucji, kliknij Finish. Rysunek 20.27. Wpisywanie nazwy skryptu i rozprowadzanie pakietu Po wykonaniu dystrybucji tworzony jest raport, który można zapisać na dysku. Wpisy w rejestrze Aby komponent mógł działać, do rejestru muszą być wprowadzone odpowiednie informacje. Komponentowi musi zostać przypisany globalny unikatowy identyfikator (GUID). Jest to identyfikator generowany w sposób losowy. Gdy instalujemy aplikację przy użyciu programu instalacyjnego utworzonego za pomocą kreatora Package and Deployment Wizard, niezbędne wpisy są tworzone automatycznie. Jeżeli nie został użyty kreator, musimy sami zarejestrować komponent. Jeżeli komponent jest w postaci pliku EXE, jest on automatycznie rejestrowany po uruchomieniu z wiersza poleceń lub poprzez dwukrotne kliknięcie jego ikony w Explorerze. Jeżeli komponent jest w postaci pliku DLL, do jego rejestracji należy użyć programu REGSVR32.EXE, który znajduje się w katalogu Windows/System (WINNT/System32 w systemie Windows NT). Aby zarejestrować komponent, wpisz poniższy wiersz w oknie Uruchom (rysunek 20.28): REGSVR32.EXE "C:\Componnets\SoundObject.Dll" Rysunek 20.28. Ręczna rejestracja ActiveX DLL przy użyciu programu REGSVR32 Można również wyrejestrowywać komponenty. Dla ActiveX EXE wykonaj ten program z wiersza poleceń dodając jako parametr /UNREGSERVER. Dla ActiveX DLL do programu REGSVR32 dodaj parametr /U. Jeżeli często rejestrujesz i wyrejestrowujesz komponenty przy użyciu REGSVR32, dodaj REGSVR32 do katalogu SendTo w katalogu Windows. Następnie możesz kliknąć prawym klawiszem myszy plik DLL i wybrać REGSVR32 z menu kontekstowego. Zgodność komponentów Jak wcześniej wspominaliśmy, komponent musi zostać prawidłowo zarejestrowany. W rejestrze Windows tworzony jest dla niego tzw. GUID. Co się stanie, gdy po zainstalowaniu komponentu zostanie on zmodyfikowany? Gdy instalujemy zmodyfikowany komponent, czy musi on zostać powtórnie zarejestrowany pod innym identyfikatorem GUID? Aby odpowiedzieć na te pytania, wróćmy do okna właściwości projektu na zakładkę Component. Na tej zakładce znajduje się kilka opcji w części zatytułowanej Version Compatibility: No Compatibility, Project Compatibility oraz Binary Compatibility. W czasie gdy tworzymy komponent, powinna być wybrana opcja Project Compatibility. Uruchamia to funkcję zarządzania kluczami w rejestrze za każdą kompilacją komponentu. Gdy komponent trafi już do klientów, zmień ustawienie na Binary Compatibility (rysunek 20.29). Rysunek 20.29. Wybrana opcja Binary Compatibility oraz wpisana nazwa wzorcowego pliku DLL W polu tekstowym poniżej tą opcją podajemy nazwę pliku DLL względem którego utrzymujemy zgodność. Za pomocą klawisza „...” możemy odszukać na dysku wzorcowy plik DLL. Teraz, gdy utworzymy nowy plik DLL, będzie on zgodny z plikiem wzorcowym. Nawet, gdy włączysz opcję Binary Compatibility, jeżeli zmienisz interfejs komponentu, wywołująca go aplikacja zawiedzie w czasie użycia komponentu. Przykładowo, gdy metoda komponentu cSound PlaySound zostanie zmieniona na PlayMusic, komponent przestanie być zgodny z poprzednimi wersjami. W takim przypadku zmień opcję zgodności na No Compatibility i roześlij do użytkowników nowy komponent wraz z aplikacją Accessa. Uważaj, aby nie usunąć wzorcowego pliku DLL, do którego odwołujesz się w opcji Binary Compatibility. Nadaj mu specjalną nazwę i zapisz w bezpiecznym miejscu. Przykładem nazwy może być Binary-cSoundObject.dll, informująca o wykorzystaniu tego pliku jako wzorca w opcji zgodności binarnej. Kiedy używamy opcji No Compatibility? Załóżmy, że po rozesłaniu komponentu cSound zdecydowałeś się usunąć metodę PlaySound, zastępując ją metodą o innej nazwie. Wszystkie aplikacje używające tego komponentu przestaną działać, ponieważ polegają one na nazwie metody PlaySound. W takim przypadku wybierz opcję No Compatibility, dzięki czemu zostanie utworzony nowy GUID. Najlepiej w takiej sytuacji utworzyć nowy pakiet instalacyjny i rozesłać go tak jak za pierwszym razem. Przed powtórnym zainstalowaniem komponentu najlepiej usunąć starą wersję. Komponent obsługi błędów W rozdziale 13. „Profesjonalna obsługa błędów” omówiony został moduł klasowy obsługi błędów, który zawierał następujące funkcje: ? Zapisywanie błędów w tabeli Accessa; ? Zapisywanie błędów w pliku tekstowym; ? Przesyłanie błędów jako e-mail; ? Zapisywanie błędów w kalendarzu Outlooka. Do tego rozdziału dołączony został jeszcze obszerniejszy moduł obsługi błędów, który używa komponentu cError (cErrorObject.dll). Na dysku znajduje się kompletny projekt ActiveX DLL, więc możesz go od razu użyć jako „globalny moduł obsługi błędów”. Przy użyciu tego pliku DLL możesz użyć tego modułu w Accessie, VB, Office i innych aplikacjach. Na dysku znajdują się aplikacje Accessa i Visual Basica, które używają komponentu cError do obsługi błędów. Dane modułu obsługi błędów Moduł obsługi błędów zapisuje dane w bazie danych Accessa o nazwie Global Error Handler Data.mdb. Baza ta zawiera dwie tabele. Informacje o błędach przechowywane są w tabeli tblErrorLog. Druga tabela, tblErrorOptions, zawiera ustawienia sposobu pracy modułu. Formularz frmErrorOptions, przedstawiony na rysunku 20.30, zapewnia łatwy dostęp do tych ustawień. Rysunek 20.30. Formularz ustawień pracy modułu obsługi błędów Dodatkowo w bazie umieszczony jest raport błędów. Komponent cError Komponent obsługi błędów wykonuje dużo operacji. Zawiera on sześć modułów klasowych: ? cComputerName – pobiera nazwę komputera. ? cDBConnection – tworzy połączenie ADO. ? cError – przetwarza informacje o błędach. ? cSound – odgrywa pliki dźwiękowe. ? cSystemInformation – pobiera informacje o komputerze, takie jak: system operacyjny, procesor, ilość zainstalowanej i wolnej pamięci. ? cUserName – pobiera nazwę użytkownika Windows. Tworzenie formantów ActiveX Visual Basic umożliwia tworzenie własnych formantów ActiveX, co daje ogromne możliwości rozszerzania aplikacji. Rodzaje formantów ActiveX W rozdziale 9. „Rozszerzanie formularzy za pomocą formantów ActiveX” opisane zostały 23 formanty wraz z przykładami ich użycia. Istnieją dwa rodzaje komponentów ActiveX: formanty interfejsu użytkownika i programowe. Formanty interfejsu użytkownika to takie, którymi zajmowaliśmy się w rozdziale 9., jak TreeView czy ListView. Użytkownicy mogą nimi manipulować. Formanty programowe są dostępne tylko dla programistów, użytkownicy nie mogą nimi manipulować. Przykładem może być ImageList lub CommonDialog. Atrybuty formantów ActiveX Formanty ActiveX nie mogą istnieć niezależnie, muszą zostać utworzone w aplikacji bazowej, zwykle na formularzu. Skompilowany formant ActiveX jest zapisany w pliku zwykle z rozszerzeniem OCX. Pojedynczy plik OCX może zawierać kilka formantów. Przykładowo MSCOMCTL.OCX, dostarczany przez Microsoft, zawiera następujące formanty ActiveX: ImageCombo, ImageList, ListView, ProgressBar, Slider, StatusBar, TabStrip, ToolBar oraz TreeView. Formanty ActiveX są wewnątrzprocesowymi serwerami automatyzacji. Dlatego formant ActiveX, który utworzysz i użyjesz w aplikacji Accessa, jest uruchamiany w jednym procesie razem z aplikacją Accessa, co daje doskonałą wydajność programu. Tworzenie programowych formantów ActiveX W Accessie, gdy potrzebny jest stoper, programiści używają zdarzenia On Timer i właściwości Timer formularza. Jedynym problemem tego podejścia jest to, że może być użyty tylko jeden stoper. Co zrobić, jeżeli potrzebujemy wielu niezależnych stoperów? Visual Basic zawiera wbudowany formant Timer, który nie jest dostępny z Accessa. Timer VB to formant programowy, który może wykonywać procedurę co zadany okres czasu. Aby użyć formantu VB Timer, umieść ją na formularzu i ustaw właściwość Interval na określony czas w milisekundach (1000 milisekund to 1 sekunda), tak jak pokazane jest na rysunku 20.31. Procedura obsługi zdarzenia Timer wykonywana jest co podany okres czasu. Można umieścić wiele stoperów na formularzu. Każdy z nich pracuje niezależnie. Rysunek 20.31. Ustawianie właściwości Interval formantu Timer W tej części rozdziału utworzysz własny formant ActiveX Timer, który może zostać użyty w Accessie i innych aplikacjach. Projekt formantu i baza Accessa wykorzystująca formant Timer zamieszczone są na dysku CD-ROM dołączonym do książki. Pamiętaj, że musisz zarejestrować (lub skompilować projekt) formant ActiveX. Utworzenie projektu dla formantu ActiveX Aby utworzyć formant ActiveX po uruchomieniu Visual Basica, wybierz ActiveX Control w oknie New Project. Rysunek 20.32. Wybór formantu ActiveX z okna dialogowego New Project Tworzenie interfejsu Po otwarciu projektu to co widzisz, wydaje się być formularzem. Nie jest to jednak formularz lecz obiekt UserControl. Obiekt ten używany jest do tworzenia interfejsu formantu ActiveX. W oknie właściwości zmień nazwę z UserControl1. na ctlTimer. Formanty ActiveX mogą zawierać inne formanty. W naszym formancie ctlTimer użyjemy formantu PictureBox pobranego z paska narzędzi (rysunek 20.33). Nazwij formant PictureBox picClock i ustaw jego właściwość Picture na CirClock.bmp z podkatalogu Bitmaps\Gauge w katalogu, gdzie zainstalowałeś Visual Basic. Ten rysunek zegara będą widzieli programiści, używając tego formantu. Rysunek 20.33. Wstawianie formantu PictureBox do UserControl Następnie przenieś formant Visual Basica Timer z paska narzędzi do naszego formantu i nazwij go ctlVBTimer (rysunek 20.34). Zauważ, że w oknie właściwości formantu znajduje się właściwość Interval. Będziemy używać tej właściwości w naszym formancie ActiveX. Rysunek 20.34. Wstawianie formantu VB Timer do UserControl Teraz zmniejszymy nasz formant. Najpierw przesuń formant VB Timer dokładnie na formant PictureBox, a następnie wybierz Send to Back z menu Format. Spowoduje to ukrycie formantu. Teraz zmniejsz rozmiar obiektu UserControl tak, aby był widoczny tylko formant PictureBox (rysunek 20.35). Rysunek 20.35. Zmniejszanie UserControl Ponieważ tworzymy formant programowy, użytkownik nigdy go nie zobaczy. We właściwościach obiektu UserControl ustaw właściwość InvisibleAtRuntime na True. Ustawianie właściwości projektu Wybierz Project1. Properties z menu Project. W oknie właściwości projektu wprowadź nazwę projektu (cTimerControl) i opis (Formant cTimer) w sposób pokazany na rysunku 20.36. Zamknij okno przez kliknięcie przycisku OK. Rysunek 20.36. Wprowadzanie nazwy i opisu projektu Zapisywanie projektu Aby zapisać projekt, wybierz Save Project z menu File. Najlepiej zapisać plik projektu (plik .vbp) i formant (plik .ctl) w tym samym katalogu, np. Formant Timer. Dodawanie metod i zdarzeń Kliknij obiekt UserControl (nie PictureBox) i przejrzyj listę właściwości. Zauważ, że nie ma tam właściwości Interval. Musisz ją tam dodać. Również należy dodać zdarzenie Timer, aby było możliwe wpisywanie kodu procedury uruchamianej po zajściu zdarzenia. Aby dodać właściwości, metody i zdarzenia, uruchom kreator ActiveX Control Interface Wizard. Użycie kreatora ActiveX Control Interface Wizard Kreator ten uruchamiamy poprzez wybranie ActiveX Control Interface Wizard z menu Add-Ins. Jeżeli nie masz go w tym menu, wybierz Add-In Manager, VB 6. ActiveX Control Interface Wizard i kliknij pole wyboru Load on Startup. Pierwszy ekran kreatora jest ekranem informacyjnym (rysunek 20.37). Kliknij przycisk Next. Rysunek 20.37. Ekran informacyjny kreatora ActiveX Control Interface Wizard Po prawej stronie ekranu mamy listę standardowych właściwości, metod i zdarzeń (rysunek 20.38). Usuń wszystkie pozycje z tej strony. Po lewej stronie okna wybierz właściwość Interval oraz zdarzenie Timer i przenieś je na prawą stronę. Kliknij Next. Rysunek 20.38. Ekran kreatora Selected Interface Members Na ekranie Create Custom Interface Members kliknij Next, ponieważ dodaliśmy już wszystkie interesujące nas elementy (rysunek 20.39). Rysunek 20.39. Ekran kreatora Create Custom Interface Members Na ekranie Set Mapping wybierz właściwość Interval oraz zdarzenie Timer i przypisz je do UserControl (rysunek 20.40). Aby przejść do kolejnego ekranu, kliknij przycisk Next. Rysunek 20.40. Ekran Set Mapping Na ekranie Set Attributes wybierz właściwość Interval i upewnij się, że typ jest ustawiony na Long (rysunek 20.41), następnie kliknij przycisk Next. Rysunek 20.41. Ekran Set Attributes Na ekranie Finished kliknij przycisk Finish (rysunek 20.42). Kreator utworzy program dodający właściwość Interval oraz zdarzenie Timer do formantu ActiveX. Można również zapisać raport na dysku. Rysunek 20.42. Ekran Finished Otwórz okno kodu dla obiektu UserControl i obejrzyj program (rysunek 20.43). Kreator utworzył Property Get oraz Property Let dla właściwości Interval. Zostało również wygenerowane zdarzenie Timer. Dodajemy kod do formantu ActiveX Kreator ActiveX Control Interface Wizard wykonał za Ciebie dużą część pracy, ale musisz dodać jeszcze kilka wierszy kodu, aby dokończyć pracę nad formantem Timer. Wywoływanie zdarzenia Nasz formant ActiveX zawiera formant VB Timer, który posiada zdarzenie Timer. Nasz formant również posiada zdarzenie Timer, które zostało dodane przez kreator ActiveX Control Interface Wizard. Musisz zsynchronizować te dwa zdarzenia tak, aby po zajściu zdarzenia Timer z formantu Visual Basica uruchamiane było zdarzenie Timer naszego formantu ActiveX. Rysunek 20.43. Kod wygenerowany przez ActiveX Control Interface Wizard Aby to zrealizować, będziesz musiał wywołać zdarzenie (ang. raise)w UserControl. W oknie programowania wybierz ctlVBTimer z listy obiektów po lewej stronie u góry okna. Następnie wybierz Timer z listy zdarzeń obok listy obiektów. Utworzona zostanie procedura obsługi zdarzenia Timer (rysunek 20.44). Wprowadź kod pokazany na rysunku 20.44, który wywoła zdarzenie Timer. Rysunek 20.44. Wywołanie procedury RaiseEvent Jaki jest efekt tych operacji? Gdy uruchomiona zostanie obsługa zdarzenia z obiektu Timer Visual Basica, wywoła on zdarzenie Timer formantu ActiveX. Uruchomi to procedurę obsługi zdarzenia utworzoną dla formantu ActiveX. Użycie zdarzenia ReadProperties Gdy programista umieszcza na formatce Twój formant Timer, ustawia właściwość Interval. Wartość właściwości Interval musi być zsynchronizowana z właściwością obiektu VB Timer. Formanty ActiveX zwykle są tworzone, gdy są dodawane do formularza przez programistów oraz gdy zawierający je formularz jest otwierany. Odpowiednim miejscem do zsynchronizowania właściwości Interval jest zdarzenie ReadProperties, ponieważ jest ono wywoływane w trakcie otwierania formularza zawierającego formant. Poniższy fragment programu ustawia wartość właściwości Interval w obiekcie VB Timer na identyczną z tej samej właściwości w Twoim formancie. ' Ustaw wartość właściwości Interval z obiektu VB Timer ' na taką samą jak w obiekcie Timer UserControl.ctlVBTimer.Interval = Me.Interval Upewnij się, że zapisałeś projekt. Testowanie formantu ActiveX w Visual Basicu Przed użyciem formantu w Accessie przetestujmy go w Visual Basicu. Mając otwarty projekt formantu ActiveX, możesz dodać projekt dla standardowego pliku EXE i przetestować formant na formularzu VB. Aby dodać nowy projekt, wybierz Add Project z menu File. W oknie New Project wybierz Standard EXE. Zauważ, że oba projekty są wyświetlane w oknie Project Explorer (rysunek 20.45). Rysunek 20.45. Dodajemy projekt do testowania formantu Ponieważ mamy teraz dwa projekty, ustaw Startup Project na Standard EXE (Project1). W oknie Project Explorer kliknij prawym klawiszem myszy Project1. i wybierz Set as Startup. Teraz, gdy będziesz uruchamiał projekt, uruchomiony zostanie Project1. Następnie zamknij wszystkie otwarte okna projektu. W menu Windows wybierz kolejno otwarte okna (oprócz Form1) i zamknij je. W trybie projektowania formularza Form1. otwórz pasek narzędzi. Zauważ, że znajduje się tam nowy formant o nazwie ctlTimer. Wstaw ten formant na formularz VB (rysunek 20.46). Nowy formant Timer może być używany identycznie jak inne formanty (np.: TextBox). Można ustawiać jego właściwości z okna właściwości oraz tworzyć procedury obsługi zdarzeń. Rysunek 20.46. Wstawianie formantu Timer na testowy formularz W oknie właściwości ustaw właściwość Interval na 5000. Ponieważ jest to czas w milisekundach, Timer będzie wywoływany co 5 sekund. Następnie wybierz Code z menu View, aby otworzyć okno programowania. Wybierz ctlTimer1. z listy obiektów oraz Timer z listy zdarzeń. W procedurze obsługi zdarzenia wprowadź proste okno komunikatu (rysunek 20.47). Rysunek 20.47. Procedura obsługi zdarzenia Timer Uruchom projekt, wybierając Start z menu Run (lub naciśnij F5). Co pięć sekund na ekranie pojawi się okno komunikatu (rysunek 20.48). Zauważ, że komponent nie jest widoczny w czasie wykonywania programu. Rysunek 20.48. Okno komunikatu otwiera się co 5 sekund Po przetestowaniu formantu w Visual Basicu użyjemy go w Accessie. Użycie formantu Timer na formularzu Accessa Przetestowanie formantu w Visual Basicu było bardzo proste. Aby użyć formantu w Accessie, należy skompilować formant. Otwórz projekt formantu ActiveX i wybierz Make cTimerControl z menu File. Zapisz plik OCX w tym samym katalogu co projekt. Formant ActiveX został skompilowany oraz zostały wprowadzone wpisy do rejestru. Otwórz nowy formularz w trybie projektowania w bazie danych Accessa. Z menu Wstaw wybierz Formant ActiveX. Wybierz formant Timer (cTimerControl) z listy, a następnie kliknij OK, aby zamknąć okno (rysunek 20.49). Rysunek 20.49. Wybór cTimerControl z okna Wstawianie formantu ActiveX Tak jak robiłeś to na formularzu VB, ustaw właściwość formantu Interval na 5000. oraz utwórz okno komunikatu w obsłudze zdarzenia Timer. Formant cTimerControl będzie teraz działać na formularzu Accessa. Tworzenie wielu formantów Timer Na początku tego rozdziału wspominaliśmy o możliwości wykorzystania zdarzenia OnTimer z formularza Accessa jako stopera. Jednak w ten sposób możliwe jest uruchomienie tylko jednego stopera. Możesz wstawić do formularza kilka formantów Timer i każdy z nich będzie pracować niezależnie (rysunek 20.50). Rysunek 20.50. Kilka formantów Timer pracujących jednocześnie Rozprowadzanie formantu ActiveX Timer Sposób rozprowadzania formantów ActiveX jest w zasadzie taki sam jak rozprowadzanie komponentów ActiveX. Przeczytać możesz o tym wcześniej w części zatytułowanej „Dystrybucja komponentów ActiveX”. Tworzenie okna właściwości W rozdziale 9. opisywaliśmy, w jaki sposób utworzyć okno właściwości, aby łatwo można było ustawiać wartości właściwości formantu ActiveX. Na rysunku 20.51. pokazane jest okno właściwości formantu ImageList. Rysunek 20.51. Okno właściwości formantu ImageList Można również utworzyć okno właściwości dla naszego komponentu Timer. W oknie projektu komponentu ActiveX wybierz Add Property Page z menu Project. W oknie dialogowym Add Property Page wybierz kreator VB Property Page Wizard. Kliknij przycisk Open w celu uruchomienia kreatora. Na ekranie startowym kliknij przycisk Next. Na ekranie Select the Property Pages kliknij przycisk Add i dodaj stronę General (rysunek 20.52). Rysunek 20.52. Kreator VB Property Page Wizard: strona Select the Property Pages Na ekranie Add Properties kliknij zakładkę General. Przesuń właściwość Interval z listy po lewej stronie okna do listy po prawej (rysunek 20.53) a następnie kliknij Next. Rysunek 20.53. Kreator VB Property Page Wizard: strona Add Properties Na ekranie Finished kliknij przycisk Finished. Kreator utworzy okno właściwości i dodatkowo może być utworzony raport. Zauważ, że okno właściwości znajduje się w oknie Project Explorer (rysunek 20.54). Rysunek 20.54. Okno właściwości w oknie Project Explorer Użycie okna właściwości Aby użyć okno właściwości, zapisz i ponownie skompiluj projekt formantu ActiveX. Otwórz formularz Accessa w trybie projektowania i dodaj formant Timer. Następnie kliknij prawym klawiszem myszy formularz i wybierz z menu cTimerControl properties. Na stronie właściwości możesz wprowadzić wartość właściwości Interval (rysunek 20.55). Rysunek 20.55. Użycie okna właściwości Użycie formantu Timer w innych aplikacjach Nasz formant nie jest ograniczony do stosowania tylko w VB i Accessie. Ten sam formant może być używany w Wordzie, Excelu, Outlooku i innych aplikacjach. Tworzenie formantów ActiveX interfejsu użytkownika Większość formantów ActiveX posiada interfejs użytkownika wykorzystywany do manipulacji formantem. W tej części utworzymy taki formant ActiveX. Przykładowy formant nazywa się cSlider i zawiera dwa formanty Slider i UpDown. Gdy użytkownik zwiększa i zmniejsza wartość za pomocą formantu UpDown, Slider się przesuwa. Projekt VB formantu ActiveX oraz baza danych Accessa, która używa formantu cSlider, są dostępne na dysku CD-ROM dołączonym do książki. Pamiętaj, aby zarejestrować formant (lub skompilować projekt) przed jego użyciem. Tworzenie interfejsu użytkownika Tak jak dla formantów programowych otwórz projekt formantu ActiveX. Dodaj formant Slider oraz UpDown do obiektu UserControl w sposób pokazany na rysunku 20.56. Zauważ, że można w jednym formancie ActiveX umieścić wiele innych formantów. Nazwij następująco obiekty: UserControl: cSlider Slider control: ctlSlider UpDown control: ctlUpDown a następnie zmniejsz obiekt UserControl. Rysunek 20.56. Dodanie formantów Slider oraz UpDown do obiektu UserControl Kliknij prawym klawiszem myszy formant ctlUpDown i wybierz Properties z menu kontekstowego, co spowoduje otwarcie okna właściwości. W oknie właściwości należy związać formant UpDown z Slider przy użyciu właściwości Buddy. Od tej chwili formanty będą działać razem bez pisania ani jednego wiersza kodu. Kliknij zakładkę Buddy w oknie właściwości. W polu tekstowym Buddy Control wprowadź ctlSlider. Spowoduje to połączenie formantów ctlSlider i ctlUpDown. Wybierz Value z listy Buddy Property, co spowoduje, że zmiana wartości ctlUpDown zmieni wartość ctlSlider. Zaznacz pole wyboru AutoBuddy i kliknij OK, aby zamknąć okno właściwości (rysunek 20.57). Rysunek 20.57. Ustawienie właściwości Buddy w oknie właściwości Ustawienie właściwości projektu Wybierz Project1 Properties z menu Project. W oknie dialogowym Project Properties wprowadź nazwę projektu (cSliderControl) oraz opis projektu (formant cSlider). Kliknięcie OK zamyka okno (rysunek 20.58). Zapisywanie projektu Zapisz projekt i obiekt UserControl, wybierając Save Project z menu File. Najlepiej zapisać projekt (plik .vbp) i obiekt UserControl (plik .ctl) w tym samym katalogu. Testowanie formantu na formularzu Visual Basica Aby przetestować formant cSlider na formularzu Visual Basica, wykonaj te same czynności co przy testowaniu formantu designtime. Rysunek 20.58. Wprowadzanie nazwy i opisu projektu w oknie właściwości projektu Użycie formantu cSlider na formularzu Accessa Otwórz projekt formantu i wybierz Make cSliderControl.ocx z menu File. Zapisz plik OCX w tym samym katalogu co plik projektu. Po tej operacji formant ActiveX jest gotowy do pracy, a w rejestrze są wszystkie odpowiednie wpisy. Otwórz formularz w trybie projektowania w bazie Accessa. Wybierz Formant ActiveX z menu Wstaw, a następnie wybierz cSliderControl z listy. Kliknięcie OK zamyka okno dialogowe. Formant cSlider działa teraz na formularzu Accessa (rysunek 20.59). Gdy zostanie kliknięty UpDown, zmieni się również pozycja formantu Slider. Rysunek 20.59. Formant ActiveX na formularzu Accessa Dystrybucja formantu ActiveX cSlider Rozprowadzanie formantów ActiveX nie różni się niczym od rozprowadzania komponentów ActiveX. Zajrzyj do części „Dystrybucja komponentów ActiveX”. Użycie formantu cSlider w innych aplikacjach Twój formant cSlider nie jest ograniczony tylko do aplikacji VB i Accessa. Ten sam formant może być użyty Wordzie, Excelu, Outlooku i innych aplikacjach. Tworzenie instalacyjnego pakietu internetowego Aby użyć formantu ActiveX cSlider na stronie WWW, użyj opcji Internet Package w kreatorze Package and Deployment Wizard. Uruchom kreator i wybierz plik projektu komponentu cSlider (plik .vbp). Kliknij przycisk Package, aby przejść do następnego ekranu (rysunek 20.60). Wybierz Internet Package i kliknij przycisk Next. Rysunek 20.60. Wybór pakietu internetowego Wybierz skrypt pakowania (rysunek 20.61). Ponieważ pierwszy raz wykonujesz pakiet internetowy, wybierz None i kliknij Next. Rysunek 20.61. Wybór skryptu pakowania Wybierz typ Internet Package i kliknij Next (rysunek 20.62). Rysunek 20.62. Wybór typu pakietu Wybierz katalog, gdzie zapisywane będą pliki pakietu i kliknij Next (rysunek 20.63). Domyślnie tworzony jest katalog pakietu jako podkatalog foldera z plikiem projektu. Rysunek 20.63. Wybór katalogu pakietu Ekran Included Files zawiera wszystkie pliki niezbędne do użycia formantu ActiveX. Dołączone są również biblioteki VB i inne niezbędne pliki (rysunek 20.64). Kliknij przycisk Next. Rysunek 20.64. Pliki zawarte w pakiecie internetowym Na ekranie File Source podaj położenie plików zawartych w pakiecie instalacyjnym (rysunek 20.65). Plik, w którym znajduje się Twój formant ActiveX (plik OCX), znajdzie się w skompresowanym pliku cab. Domyślnym ustawieniem dla bibliotek VB i innych plików Microsoftu jest witryna WWW firmy Microsoft. Możesz pozostawić domyślne ustawienie, ponieważ w razie potrzeby użytkownicy załadują potrzebne pliki z serwera WWW Microsoftu. Ustaw serwer WWW Microsoftu jako położenie bibliotek VB i innych plików Microsoftu. Microsoft zapewnia większą przepustowość łącz niż większość firm, co zapewnia poprawne załadowanie aktualnych plików. Na ekranie Safety wymieniony jest tylko formant cSlider. Wybierz Yes dla opcji Safe for Scripting oraz Yes dla Safe for Initialization (rysunek 20.66). Jest to Twoja deklaracja, że komponent jest bezpieczny. Kliknij Next, aby przejść do następnego ekranu. Na ostatnim ekranie możesz podać nazwę skryptu, aby zapisać ustawienia wszystkich opcji w kreatorze. Używając zapisanego skryptu, nie trzeba ponownie wybierać ustawień w kreatorze (rysunek 20.67). Kliknij Finish, aby wygenerować pakiet. Rysunek 20.65. Wybór źródła plików Rysunek 20.66. Ustawianie ustawień bezpieczeństwa Rysunek 20.67. Wybór nazwy dla skryptu oraz tworzenie pakietu Po zakończeniu pracy kreator tworzy raport, który może zostać zapisany na dysku. Użycie formantu cSlider na stronie WWW Otwórz katalog, w którym zapisałeś pakiet internetowy. Zauważ, że został utworzony plik cSliderControl.htm (rysunek 20.68). Dwukrotne kliknięcie pliku cSliderControl.htm otwiera stronę w przeglądarce internetowej. Formant cSlider działa w przeglądarce identycznie jak w formularzach VB i Accessa. Rysunek 20.68. Pliki w katalogu pakietu internetowego Nie wszystkie przeglądarki obsługują formanty ActiveX. Jednak Microsoft Internet Explorer, jak widać na rysunku 20.69, obsługuje formanty ActiveX. Rysunek 20.69. Formant cSlider na stronie WWW Aby zobaczyć kod HTML strony WWW, otwórz ją w Internet Explorerze i wybierz Źródło z menu Widok. Zauważ, że w kodzie HTML znajduje się formant cSlider oraz jego classID (rysunek 20.70): --> Jeżeli chcesz używać formantu cSlider na innej stronie WWW, skopiuj kod obiektu HTML z jednej strony do innej. Rysunek 20.70. Formant ActiveX w kodzie HTML Część VII Zagadnienia wielodostępu W tej części: ? Zagadnienia wielodostępu, serwer plików, blokowanie. ? Replikacja i JRO. ? Bezpieczeństwo. Rozdział 21. Zagadnienia wielodostępu, serwer plików, blokowanie W tym rozdziale: ? Konflikty. ? Konfiguracja. ? Blokady Accessa i Jet. ? Blokady Oracle / SQL Server. Gdy baza danych Accessa opuszcza swoje środowisko programistyczne i zaczyna być używana przez ludzi, dla których była utworzona, jest narażona na efekty uboczne wielodostępu. Najbardziej irytującym problemem powodowanym przez wielodostęp są konflikty w dostępie do rekordów. Konflikty Ważne jest, aby pamiętać, że każda wieloużytkownikowa baza danych jest narażona na problemy powodowane przez blokady i konflikty. Ukrywanie komunikatów o błędach lub nadzieja na to, że wszystko dobrze pójdzie, nie usunie problemów. Mimo że zagadnienia wielodostępu wydają się skomplikowane, dokładne zrozumienie, w jaki sposób Jet blokuje dane i zarządza wieloma użytkownikami, nie jest trudne. Pozostawienie nierozwiązanych zagadnień wielodostępu tworzy zwykle dużo większe problemy nękające użytkowników, klientów i wpływające na naszą reputację. Nieprawidłowe rozwiązanie problemów wielodostępu prowadzi do następujących problemów: ? Nowe rekordy nie są zapisywane – nie ma nic gorszego dla użytkownika wprowadzającego dane do aplikacji, jak zniknięcie wprowadzonych danych. Fakt, że prawdopodobnie nie będzie mógł powtórzyć tego błędu, nie znaczy, że problem nie istnieje, raczej mają rację mówiąc, że aplikacja jest niepewna. ? Zmiany nie zostają zapisane – klient może nawet nie zauważyć, że zmiany nie zostały zapisane. Jednak kiedyś w przyszłości arkusz bilansu będzie nieprawidłowy lub nie będzie zgadzać się stan magazynu, albo zamówienie ważnego klienta zostanie wysłane pod zły adres. Są to skomplikowane problemy i często nie są wykrywane na czas. ? Użytkownicy mogą otrzymywać tajemnicze komunikaty, że system nie może zwrócić żądanych danych. Mimo że jest to mniej dramatyczna sytuacja, nie należy rozczarowywać użytkowników, gdy system załamuje się przy niewielkim obciążeniu. W Accessie zagadnienia wielodostępu to nie tylko blokowanie i zdejmowanie blokad. Ponieważ aplikacja przechowywana jest w pojedynczym pliku, a aplikacja ma formularz związany bezpośrednio z danymi, dyskusja na temat wielodostępu musi zawierać zagadnienia dotyczące zarządzania plikami, konfiguracji, technik tworzenia interfejsu użytkownika oraz właściwości kwerend i formularzy. Zwykle aplikacja Accessa wymaga kombinacji kilku taktyk, ponieważ napotkasz różne problemy wielodostępu w kilku różnych miejscach aplikacji. Konfiguracja Aplikacja Accessa może być skonfigurowana na kilka sposobów, aby przystosować ją do obsługi wielu użytkowników. Każdy z nich ma swoje wady i zalety. Podstawowe zalety i wady są opisane poniżej. ? Konfiguracja sieciowa. W takiej konfiguracji pojedynczy plik MDB umieszczony jest na serwerze sieciowym, a użytkownicy uruchamiają aplikację z tego serwera. Zaletą takiej konfiguracji jest łatwość konserwacji, ponieważ wystarczy zamienić jeden plik programu. Jednak wszystkie formularze, raporty, moduły, kwerendy oraz Access i biblioteki DLL muszą być przesłane poprzez sieć, co powoduje duże obciążenie sieci prowadzące do obniżenie wydajności aplikacji. W tej konfiguracji do manipulacji danymi prawdopodobnie używasz formularzy związanych. Jak jest to przedstawione później, formularze związane powodują konflikty przy jednoczesnym dostępie do danych. ? Oddzielenie danych od programu. Taka konfiguracja jest zwykle nazywana konfiguracją z użyciem zdalnej bazy danych (zauważ, że określenie „zdalny” przechodzi transformację w czasach Internetu i niedługo może okazać się archaiczne w tym kontekście), ponieważ dane są oddzielone od programu, ale silnik bazy danych pozostaje na maszynie użytkownika. W odróżnieniu od konfiguracji klient – serwer silnik bazy danych Accessa pobiera dane, blokuje je oraz zwalnia blokady w pliku MDB na serwerze. Zdolność do wielodostępu w takiej konfiguracji zależy od zdolności silników bazy danych wszystkich użytkowników do współdziałania oraz od serwera plików, który utrzymuje cały ruch w sieci. Jak do tej pory jest to zalecana metoda pisania aplikacji wielodostępnych w Accessie. Główną zaletą tej metody jest dobra wydajność oraz, jeżeli jest odpowiednio zaimplementowana, kontrola nad danymi. Ponieważ dane znajdują się na serwerze sieciowym, tylko one są przesyłane, więc obciążenie sieci jest znacznie zmniejszone. Główną wadą takiego rozwiązania jest konieczność zainstalowania na każdym komputerze klienta Accessa oraz aplikacji jako plik MDB lub MDE (skompilowana wersja formularzy, kwerend, raportów i modułów aplikacji), co zwiększa nakłady na utrzymanie systemu. ? Replikacja. W konfiguracji z użyciem replikacji użytkownicy współdzielą dane, ale nie są one wspólne jak przy użyciu konfiguracji sieciowej czy zdalnej bazy danych. Każdy użytkownik lub małe grupy użytkowników mają prywatne kopie danych, które są aktualizowane między sobą przy użyciu mechanizmu replikacji Jet. Zaletą tego, że użytkownicy mają swoje kopie danych, jest wyeliminowanie blokad, ale są one zastąpione problemami replikacji, które są równie skomplikowane jak problem konfliktów. Inną zaletą jest umożliwienie użytkownikom asynchronicznej replikacji danych, jeżeli odłączają się od sieci. Wadą tej metody jest to, że nawet w małych grupach użytkowników używających wspólnych danych aplikacja musi radzić sobie zarówno z problemami wielodostępu jak i replikacji. I na koniec, replikowane bazy danych są zwykle większe od tych, które nie używają tej techniki. ? Konfiguracja klient-serwer. Access 2000 wreszcie umożliwia programistom tworzenie aplikacji klient-serwer przy użyciu projektów dostępu do danych (ADP). W konfiguracji klient-serwer zarówno dane jak i silnik bazy danych pozostają zdalne. Serwer Oracle, SQL Server lub inny centralnie zarządza danymi i blokadami oraz dba o zapewnienie wielodostępu. Nie znaczy to, że nie musisz się tym przejmować, znaczy to, że musisz brać pod uwagę inny zestaw założeń, możliwości i reguł. Najważniejszą zaletą takiej konfiguracji jest wydajność, stabilność i możliwość obsłużenia dużej liczby użytkowników. Wadą jest koszt rozwiązania oraz zwiększony stopień skomplikowania. W tym rozdziale zajmiemy się zagadnieniami wspólnymi dla konfiguracji sieciowej, zdalnej bazy danych oraz klient-serwer. Użycie replikacji przedstawione będzie w rozdziale 22. „Replikacja i JRO”. W Accessie mamy możliwość wielu ustawień na poziomie bazy danych, na formularzach, kwerendach, zestawach rekordów oraz na poziomie wykonania programu, które należy odpowiednio ustawić, aby aplikacja mogła niezawodnie obsługiwać wielu użytkowników. Prawie wszystkie tematy przedstawiane w tym rozdziale znajdują się w różnych miejscach aplikacji oraz techniki lub kombinacje technik różnią się od rodzaju aplikacji. Podstawą sukcesu w wielodostępnej aplikacji jest planowanie, przewidywanie i testowanie. Access i blokady Jet Jet posiada schemat blokowania, który pozwala na efektywne obsługiwanie wielu użytkowników. Gdy Jet jest używany w Accessie, w odróżnieniu od użycia go w VB lub innym środowisku programowania, istnieje kilka domyślnych ustawień, które powinieneś rozpatrzyć. Ta część rozdziału zajmuje się tymi zagadnieniami. Omówienie blokowania Przed oddaniem wielodostępnej bazy danych musi być ona umieszczona w miejscu, do którego mają dostęp użytkownicy, oraz baza musi zostać otwarta w trybie współdzielonym. Można to wykonać na kilka sposobów. W oknie Opcje (Narzędzia, Opcje, Zaawansowane) znajduje się opcja Domyślny tryb otwarcia. Można ustawić tryb wyłączny (tylko jeden użytkownik) lub tryb udostępniony. Gdy wybrany jest tryb wyłączny, bazę danych może otworzyć tylko jeden użytkownik. Gdy baza danych dostanie otwarta w tym trybie, Access zmienia nagłówek pliku LDB lub pliku blokad Accessa (więcej informacji o tym pliku w części rozdziału: „Plik LDB”), aby zapobiec otwarciu bazy przez innego użytkownika. Oczywiście ta opcja nie może być używana w aplikacjach wielodostępnych. Jednak czynności konserwacyjne, jak kompresowanie i naprawianie, muszą być wykonywane przy bazie otwartej na wyłączność. Ustawienie trybu udostępnionego pozwala na otwarcie bazy danych przez kilku użytkowników jednocześnie. Przy otwieraniu bazy informacja o użytkownikach jest zapisywana w pliku LDB oraz przeprowadzana jest negocjacja blokowania i zwalniania stron i rekordów. Ustawienie tych opcji jest możliwe przy użyciu parametrów w wierszu poleceń przy uruchamianiu Accessa. W tabeli 21.1 opisane są niektóre parametry. Tabela 21.1. Parametry wiersza poleceń Accessa Parametr Opis /Excl Otwiera bazę na wyłączność. Może być użyte nawet z bazą ustawioną na tryb udostępniony /Ro Tylko do odczytu. Baza jest dostępna dla wielu użytkowników, ale nie mogą być zapisane zmiany. Nie są zakładane żadne blokady Brak Jeżeli nie zostanie podany żaden parametr, baza otwierana jest w trybie ustawionym w oknie opcji Nie można pozwolić użytkownikom na otwarcie bazy na wyłączność, jeżeli ma pracować na niej wielu użytkowników. Można się przed tym zabezpieczyć, odbierając mu prawo Otwórz z wyłącznością z grupy użytkowników. Szczegółowo zostało to opisane w rozdziale 23. „Bezpieczeństwo”. Programista ma możliwość ustawienia w bazie domyślnego trybu blokowania rekordów. Możliwe są dwa tryby: blokowanie rekordu i blokowanie strony. Blokowanie stron kontra blokowanie rekordów W przeszłości Access był szczególnie podatny na konflikty z powodu sposobu zapisu rekordów i ich blokowania. Ponieważ Access posiadał rekordy o zmiennej wielkości, nie dało się łatwo zaimplementować blokowania rekordów. Access zapisywał rekordy na stronach o wielkości 2KB (w silniku bazy danych Accessa 2000 – Jet 4.0 strony mają po 4KB). Gdy rekord był blokowany umyślnie bądź przypadkowo, blokowana była cała strona. Zablokowanie strony blokowało również inne rekordy, które zapisane były na tej stronie. Mimo że ten sposób blokowania jest bardzo wydajny, połączone jest to z częstymi konfliktami i ogranicza ilość użytkowników jednocześnie korzystających z bazy. Jest to często krytykowane ograniczenie przy tworzeniu aplikacji w Accessie. W Accessie 2000, Jet 4.0 daje programistom możliwość wyboru pomiędzy blokowaniem stron a blokowaniem rekordów. Teraz użytkownik może zablokować tylko edytowany rekord bez niepotrzebnego blokowania innych rekordów. Ponieważ rekord może zostać zablokowany tylko na chwilę (jak w przypadku wykonywania instrukcji SQL Delete, Update lub Insert), szansa konfliktu dwóch użytkowników podczas edycji rekordu jest mniejsza, niż gdy zostanie zablokowanych kilka rekordów podczas blokowania strony. Do tej pory szansa konfliktu była zwielokrotniana przez ilość rekordów na stronie, co było trudne do określenia. Ilość rekordów na stronie zależy od rozmiaru rekordu oraz kiedy był wprowadzony, więc trudno jest przewidzieć potencjalne konflikty. Blokowanie rekordów jest domyślnym ustawieniem, jednak nie oznacza, że jest to zawsze najlepszy wybór. W sytuacjach, gdy wydajność jest najważniejsza a potencjalne konflikty są rzadkie lub możliwe do zarządzania, nakład czasu na blokowanie rekordów może okazać się zbyt duży. Rozważmy system obsługi bankowego kantoru wymiany walut, gdzie rekordy są częściej wprowadzane niż poprawiane. Ponieważ taki system powinien działać szybko, z rzadkimi przestojami powodowanymi przez konflikty. W przedstawianym przez nas przypadku blokowanie stron może być odpowiednie. W innym przypadku, gdzie współbieżność jest duża i jest niedopuszczalna edycja więcej niż jednego rekordu naraz, blokowanie rekordów odpowiada tym warunkom. Jest to szczególnie ważne, gdy rekordy są często zmieniane. Wracając do przykładu banku, baza danych obsługująca operacje na rachunkach klientów musi być cały czas dostępna. Powinna ona zablokować rekord na wyłączność w trakcie jego edycji, ponieważ występuje ryzyko zapisania zmian zrobionych przez innego użytkownika. Ponadto, gdy jest zmieniany rekord rachunku, nie może on blokować żadnych sąsiednich rachunków. Blokowanie rekordów jest również odpowiednie w sytuacjach, gdy rekord musi być otwarty przez dłuższy okres czasu i zabezpieczony przed zmianą przez innych użytkowników. Przykładem może być kontrola zgodności z przepisami informacji o kliencie lub sprawdzenie zdolności kredytowej. Nie chcesz, aby rekord zmienił się, dopóki nie skończysz kontroli. Zwykle, gdy użytkownik trzyma zablokowany rekord przez dłuższy czas, skutkuje to zablokowaniem kilku innych rekordów na czas edycji. Dobra praktyka mówi, aby nie blokować rekordu na długi okres czasu chyba, że jest to absolutnie konieczne. Od teraz programiści mają możliwość kontrolowania wielodostępu na poziomie stron lub rekordów. Taka kombinacja daje dużą elastyczność. Plik LDB Plik blokad jest plikiem tymczasowym tworzonym przez Access w czasie otwierania bazy danych. Zawiera on informacje o blokadach założonych w bazie danych oraz użytkownikach używających bazy. Gdy baza jest zamykana, plik zostaje usunięty. Plik ten ma nazwę identyczną z nazwą obsługiwanej bazy danych i rozszerzenie LDB. Zawsze tworzony jest w tym samym katalogu co baza danych. Optymistyczne i pesymistyczne blokowanie rekordów W aplikacjach wieloużytkownikowych jedynym bezpiecznym założeniem, jakie może zrobić programista, jest możliwość wystąpienia konfliktów przy dostępie użytkowników do jednego rekordu. Jedynym sensowną rzeczą do zrobienia jest zaplanowanie, w jaki sposób obsługiwać te sytuacje poprzez odpowiednie ustawienie opcji blokowania. Są to zasadniczo dwie opcje: blokowanie optymistyczne i pesymistyczne. Blokowanie optymistyczne Jako domyślne w Accessie, blokowanie optymistyczne jest najłatwiejsze do implementacji i zwykle jest dobrym wyborem. Gdy rekord jest optymistycznie zablokowany, zakłada się, że nie wystąpi konflikt i rekord jest blokowany tylko na czas zapisu do bazy. Powoduje to, że dane są łatwo dostępne, ponieważ nikt nie blokuje na długo dostępu do danych. Podczas gdy użytkownik wprowadza zmiany do rekordu, inni użytkownicy mogą również zmieniać ten rekord i pierwszy użytkownik, który zapisze dane, zablokuje innych użytkowników. Mimo że optymistyczne blokowanie jest łatwe do wykonania, zwykle powoduje kilka problemów. Ten typ blokowania wywołuje najstarsze zagadnienie wielodostępności – czyje zmiany powinny zostać zapisane. Jeżeli Karol otworzy rekord i umieści na nim optymistyczną blokadę, nic nie przeszkodzi Katarzynie otworzyć ten sam rekord, aby wprowadzić zmiany. Gdy Katarzyna zapisze swoje zmiany przed Karolem, Karol zobaczy komunikat: "Silnik bazy Microsoft Jet zatrzymał proces, ponieważ inny użytkownik próbuje zmienić te same dane w tym samym czasie." Wcześniejsze wersje Accessa przedstawiały okno dialogowe, które pozwalało użytkownikowi wybrać między nadpisaniem zmian innego użytkownika, niezapisywaniem własnych zmian lub skopiowaniem danych do schowka. Okno konfliktu przy zapisie nie przedstawiało odpowiednio dużo informacji, aby dokonać sensownego wyboru wśród prezentowanych opcji. Nowe okno konfliktu przy zapisie prze to, że nie oferuje żadnego wyboru, jest jednoznaczne. W dalszej części rozdziału przedstawimy konflikty przy zapisie i omówimy kilka sposobów na lepszą obsługę błędów. Blokowanie pesymistyczne Blokowanie pesymistyczne jest odwrotnością blokowania optymistycznego. Gdy rekord jest pesymistycznie zablokowany, nikt z innych użytkowników nie może go otworzyć aż do jego zapisania. Wiele systemów baz danych używa tego sposobu blokowania, więc powinno być znane wielu programistom a użytkownicy zaznajomieni z jego konsekwencjami. Mimo że blokowanie pesymistyczne eliminuje konflikty przy zapisie, nie jest pozbawione problemów. Gdy zostanie uruchomione blokowanie pesymistyczne, spada dostępność i współbieżność dostępu do danych obniża się. Jeżeli zostanie użyte blokowanie stron, problem zostanie powiększony, ponieważ zablokowane zostaną również wszystkie rekordy na stronie. Jeżeli proces edycji danych jest czasochłonny, a pracuje równocześnie wielu użytkowników, blokady pesymistyczne powinny być dokładnie przemyślane. Niektóre aplikacje, jak obsługa sprzedaży i magazynu, prawdopodobnie skorzystają na zastosowaniu blokad pesymistycznych, ponieważ jest tu bardzo ważna kontrola rekordów, jednak systemy kontroli czasu prawdopodobnie przez zastosowanie pesymistycznego blokowania zanotują spadek wydajności. Wiele z tych ostrzeżeń dotyczy blokowania pesymistycznego w kontekście mechanizmu blokowania stron Accessa. Teraz, gdy dostępne jest blokowanie rekordów, pesymistyczne blokowanie powinno być częściej akceptowane i używane. Blokowanie rekordów Najważniejszą zaletą blokowania rekordów jest zwiększenie wielodostępu. Przez możliwość zablokowania tylko zmienianego rekordu więcej użytkowników może dostać się do danych bez wystąpienia konfliktów przy blokowaniu lub zapisie. Użycie blokowania rekordów pozwala programistom na użycie blokowania pesymistycznego w większej ilości aplikacji. Użytkownicy zauważą, że zachowanie aplikacji jest bardziej im znane i bardziej intuicyjne. Użytkownik oczekuje, że po prostu otworzy rekord, zmieni go i zmiany zostaną zapisane. W poprzednich wersjach Accessa blokowanie stron powodowało, że pesymistyczne blokowanie było zbyt kosztowne w przypadku dużej ilości użytkowników. Użytkownicy musieli się liczyć z tym, że ktoś inny zablokuje ich zmiany, a programiści będą obmyślać sposoby na przewidywanie zachowań użytkowników (rozszerzanie rekordów, tabele tymczasowe itd.). Blokowanie rekordów jest najważniejszym ulepszeniem Jet 4.0 i powinno spowodować utworzenie wielu popularnych i elastycznych aplikacji. Właściwość RecordLocks w interfejsie związanym Gdy w Accessie otwierany jest związany formularz lub zestaw rekordów, możliwe jest nałożenie blokady na bazowy zestaw rekordów. Oczywiście opcja ta działa tylko w przypadku rozwiązań z użyciem Jet, gdy używamy architektury klient-serwer, Access zawsze przyjmuje opcję „Bez blokowania”. Programista ma możliwość wyboru z: ? Bez blokowania – jest to odpowiednik blokowania optymistycznego. ? Edytowany rekord – jest to odpowiednik blokowania pesymistycznego. ? Wszystkie rekordy – blokuje wszystkie rekordy w zestawie. Należy ostrożnie używać go w aplikacjach wielodostępnych. Mimo że połączenie interfejsu użytkownika z danymi jest najprostszą metodą udostępnienia użytkownikom danych, jednak robiąc to tracisz możliwość kontroli. Na formularz podłączonym do pesymistycznie zablokowanego rekordu użytkownik dostanie przekreślone O w pasku wyboru rekordu, jednak nie wiadomo, kto zablokował rekord. Jeżeli pasek wyboru rekordu jest niewidoczny, użytkownik usłyszy tylko sygnał dźwiękowy. Metody blokowania silnika Jet Blokady są normalną i niezbędną operacją w bazie danych, jednak aby upewnić się, że blokady są właściwego typu i czasu trwania, powinieneś mieć możliwość dostania informacji o tym kiedy nastąpiła blokada. W tej części opisane zostało rozpoznawanie typów blokad w aplikacji, aby sprawdzić, czy projekt aplikacji jest właściwy. Określanie stanu blokad Jak jest to opisane wcześniej, blokowanie rekordu lub strony jest wykonywane w różnych momentach w zależności, czy jest to blokowanie optymistyczne, czy pesymistyczne. Także różne części aplikacji (lub różne aplikacje) mogą używać różnych typów blokowania tych samych danych w tym samym czasie. Z tego powodu mogą wystąpić różne typy błędów. Otrzymany błąd zależy od stanu blokady. ADO dostarcza właściwości LockType w obiekcie recordset, która wskazuje na rodzaj blokady, jaka nałożona zostanie na rekord w czasie jego edycji. Właściwość tę można zmieniać przed otwarciem zbioru rekordów, a po jego otwarciu można ją tylko odczytywać. W tabeli 21.2 opisane są stałe używane dla właściwości LockType w Mictosoft.Jet.OLEDB.4.0. Inni dostawcy OLEDB dostarczają różnych opcji. Aby sprawdzić, która opcja jest dostępna, użyj metody .Supports z parametrem adUpdate lub adUpdateBatch. Tabela 21.2. Stałe typów blokowania w Jet 4.0 udostępniane przez dostawcę Mictosoft.Jet.OLEDB.4.0 Stała Opis AdLockReadOnly Domyślne ustawienie. Zbiór obiektów nie może być zmieniany, jest otwierany tylko do odczytu i rekordy nie są blokowane AdLockPessimistic Pesymistyczne blokowanie rekordów AdLockOptimistic Optymistyczne blokowanie w czasie wywoływania zdarzenia Update ADLockBatchOptimistic Optymistyczne blokowanie dla uaktualniania wsadowego adLockPessimistic nie działa, gdy właściwość CursorLocation jest ustawiona na adUseClient, jednak nie wystąpi żaden błąd. Jet podstawi inny podobny typ blokowania. Dzieje się tak, ponieważ używając adUseClient, serwer nie śledzi bieżącego rekordu, więc nie jest możliwe pesymistyczne blokowanie. Podzbiór ADOR (ADOR to podzbiór modelu obiektów ADO, który dostarcza tylko obiektów Recordset i Field, które mogą być tworzone lub przesyłane z serwera do klienta), dostarcza tylko typu blokowania adLockOptimisticBatch. Znajomość stanu blokady rekordu jest ważne w czasie tworzenia, testowania i utrzymywania aplikacji. Każdy proces, który obsługuje dane, powinien być sprawdzony, czy spełnia założenia projektu. Wykonanie tego jest proste. Zatrzymaj wykonanie programu i sprawdź wartość właściwości LockType w obiekcie recordset (rysunek 21.1). Rysunek 21.1. Właściwość LockType obiektu recordset przedstawia rodzaj blokady Inna właściwość wskazuje na to, czy recordset był zmieniany. Właściwość EditMode zmienia się z początkowego adEditNone na adEditInProgress w trakcie edycji rekordu oraz znów na adEditNone po udanym zapisaniu rekordu. Inne wartości właściwości EditMode opisane są w tabeli 21.3. Wartość właściwości EditMode wskazuje na stan bufora używanego do zmiany i tworzenia rekordów. Możesz użyć tej wartości do sprawdzenia, czy potrzebujesz wywołać metodę Update lub CancelUpdate, gdy operacja została przerwana. Tabela 21.3. Wartości właściwości EditMode dla obiektu recordset ADO Stała Opis adEditNone Rekord nie był zmieniony adEditInProgress Dane w rekordzie są zmienione, ale nie były zapisane adEditAdd Występuje, gdy wywołana została metoda AddNew. Wskazuje na to, że w buforze jest nowy rekord niezapisany do tabeli adEditDelete Bieżący rekord został skasowany Sprawdzanie blokad Sposobem na sprawdzenie, jaka blokada została nałożona na rekord, jest odczytanie wartości właściwości LockType i EditMode, ale większym problemem jest sprawdzenie, czy została nałożona blokada przez innego użytkownika na potrzebne nam dane. Jedynym sposobem na zweryfikowanie blokad jest spowodowanie konfliktu. Dostawca Jet OLEDB zwraca niektóre informacje o blokadach użytkownika w przypadku wystąpienia błędu. W przypadku konfliktu należy sprawdzić wartość właściwości Connection.Errors(index).SQLState aby stwierdzić, jaki błąd wystąpił. W tabeli 21.4 wymienione zostały niektóre kody błędów powodowanych przez konflikty, które można odczytać z właściwości SQLState. Tabela 21.4. Błędy blokowania dostarczone przez dostawcę Jet 4.0 OLEDB Kod Komunikat 3006 Baza danych jest otwarta na wyłączność 3008 Tabela jest otwarta przez innego użytkownika lub otwarta jest przez interfejs użytkownika i nie może być zmieniana przez program 3009 Próbujesz zablokować tabelę w czasie jej otwierania, ale nie może być zablokowana, ponieważ jest używana. Poczekaj chwilę i ponów operację 3027 Nie można uaktualniać rekordu. Baza danych lub obiekt jest tylko do odczytu 3046 Nie można zapisać, zablokowane przez innego użytkownika 3158 Nie można zapisać rekordu, zablokowany przez innego użytkownika 3164 Pole nie może być zmienione, ponieważ inny użytkownik lub proces zablokował związany rekord lub tabelę 3186 Nie można zapisać, zablokowane przez użytkownika na komputerze 3187 Nie można odczytać, zablokowane przez użytkownika na komputerze 3188 Nie można zapisać, zablokowane przez inną sesję na tym komputerze Tabela 21.4. Błędy blokowania dostarczone przez dostawcę Jet 4.0 OLEDB (ciąg dalszy) Kod Komunikat 3189 Tabela jest zablokowana na wyłączność przez użytkownika na komputerze 3197 Silnik bazy Microsoft Jet zatrzymał proces, ponieważ inny użytkownik próbuje zmienić te same dane w tym samym czasie 3202 Nie można zapisać, zablokowane przez innego użytkownika 3211 Silnik bazy danych nie może zablokować tabeli , ponieważ jest używana przez inną osobę lub proces 3212 Nie można zapisać, zablokowane 3218 Nie można zapisać, zablokowane przez użytkownika na komputerze 3260 Tabela Jest zablokowana na wyłączność przez użytkownika na komputerze 3261 Nie można zablokować tabeli , używana przez użytkownika na komputerze Tablica błędów zawiera inne użyteczne informacje dotyczące błędu blokowania, informacje o blokadach innego użytkownika. Właściwość NativeError oraz Number informuje o blokadzie wstrzymującej twoją operację. Kombinacje wartości i ich znaczenie przedstawione są w tabeli 21.5. Tabela 21.5. Sposób, w jaki wartości NativeError i Number wskazują na typ blokady Użytkownik Właściwość Wartość Typ blokady Ty Connection.Errors(0).NativeError -533791822 Pesymistyczna Ty Connection.Errors(0).Number -105514571 Optymistyczna Inny Connection.Errors(0).NativeError -2147467259 Pesymistyczna Inny Connection.Errors(0).Number -2147217887 Optymistyczna W tej chwili możesz niewiele zrobić z tymi wartościami, może poza użyciem ich jako wartości opóźnienia następnej próby zapisu. Zapamiętaj te właściwości, mogą być one przydatne w przyszłości. Użycie blokowania stron Access przez długi czas nie potrafił blokować rekordów (istniało pewne obejście problemu) i zamiast tego blokował całą stronę, jak to zostało opisane wcześniej w tym rozdziale. Aby skorzystać ze wzrostu wydajności blokowania stron, wyłącz domyślne blokowanie rekordów. Aby to zrobić wybierz Narzędzia?Opcje?Zaawansowane i wyłącz Otwórz z blokowaniem na poziomie rekordu. Obsługa błędów blokowania Każdy system wieloużytkownikowy powinien uprzedzać komunikaty błędów. Różne systemy obsługują błędy w różny sposób. Różne systemy dostarczają różnej informacji dla programistów i użytkowników w przypadku wystąpienia błędu blokady. W tej części omówimy niektóre ustawienia blokowania i błędy blokowania, które możesz napotkać w trakcie programowania w Accessie 2000. Przedstawione zostaną niektóre techniki obsługi błędów i unikania ich. Ustawienia blokowania Accessa Najlepszą metodą obsługi błędów wielodostępu jest unikanie ich. Access dostarcza kilka właściwości, które mogą zostać ustawione, aby zmniejszyć częstotliwość konfliktów. Opcje te znajdują się na zakładce Zaawansowane okna dialogowego Opcje. Jednak nie mogą same obsłużyć wszystkich błędów. ? Liczba ponownych prób aktualizacji. Tyle razy Access powtarza próby zapisu lub aktualizacji rekordu, gdy wystąpiła blokada. Dopuszczalne wartości 1–10. ? Interwał odświeżania ODBC. Interwał odświeżania w sekundach w czasie używania bazy danych ODBC. Dopuszczalne wartości 1–3600. ? Interwał odświeżania. Interwał odświeżania w sekundach w przypadku odświeżania rekordów w formularzu lub arkuszu danych. Dopuszczalne wartości 1–32766. ? Interwał ponawiania prób aktualizacji. Czas w milisekundach między próbami zapisu zmienionego rekordu, gdy wystąpiła blokada. Dopuszczalne wartości 1–32766. Konflikty zapisu Błąd konfliktu zapisu (błąd numer 3197 w tabeli 21.4) jest jednym z najbardziej zagmatwanych błędów w wieloużytkownikowym środowisku Accessa. Użytkownik 1 otwiera rekord z optymistyczną blokadą i w trakcie, gdy edytuje rekord Użytkownik 2 otwiera ten sam rekord, zmienia go i zapisuje. Gdy Użytkownik 1 kończy pracę i próbuje zapisać go, wystąpi błąd. We wcześniejszych wersjach Accessa, wyświetlane było mylące okno dialogowe pytające użytkownika, czy nadpisać zmiany innego użytkownika (mimo że nie wiadomo, jakie to zmiany), anulować własne zmiany (nigdy nie było to popularne) lub skopiować dane do schowka. Systemowa obsługa tego błędu została zmieniona. W Accessie 2000 błąd konfliktu przy zapisie powoduje anulowanie zmian użytkownika. Mimo że brzmi to brutalnie, jednak lepiej, gdy zakłada się, że większość aplikacji wielodostępnych w Accessie jest tworzona szybko przez ludzi, którzy mogą nie mieć dostatecznej wiedzy na temat zagadnień wielodostępności. Poza tym użytkownik nie powinien odpowiadać na pytania, o których nawet nie pomyślał, że może zostać zapytany. Jeżeli aplikacja zakłada inne traktowanie konfliktów zapisu, można napisać własny podprogram obsługi błędów. Zablokowany rekord Gdy w czasie normalnego używania aplikacji Użytkownik 1 spróbuje zablokować rekord, który jest zmieniany przez Użytkownika 2, Użytkownik 1 spowoduje błąd „Zablokowany rekord” (błąd numer 3260 w tabeli 21.4). Typowa procedura obsługi błędów spróbuje kilka razy zablokować rekord przed wyświetleniem komunikatu o blokadzie. Jeżeli Użytkownik 2 zablokował rekord w sposób pesymistyczny, rekord zostanie zwolniony zaraz po zapisaniu do bazy danych. Jest to zwykle krótki okres czasu. Transakcje Transakcje łączą oddzielne operacje tak, aby zostały wykonane jak jedna. Zbiór instrukcji może zostać wykonany w całości prawidłowo (zostają potwierdzone – commit) lub w całości się nie udać (zostają wycofane – rollback). Gdy transakcja nie uda się, zmiany zostają cofnięte do stanu sprzed rozpoczęcia transakcji. Zapewnia to, że gdy przedmiot zostanie zarejestrowany na rachunku, zostanie zdjęty z magazynu. Gdy na jednym rachunku jest przychód, to na drugim rozchód i gdy rekord jest zmieniany, tworzony jest zapis w dzienniku operacji. W wysoce zmiennym środowisku aplikacji wielodostępnej użytkownik wykonujący te operacje może napotkać błąd zablokowanego rekordu w jednej części procesu, co może spowodować błąd w bilansie na koncie, sztucznie wypełniony magazyn lub wykonane zmiany, ale nie w pełni zarejestrowane. W skrócie, transakcje pomagają utrzymać integralność danych przy częstych i wielokrotnych blokadach rekordów. Przetwarzanie transakcyjne powinno być użyte w aplikacjach wielodostępnych wszędzie tam, gdzie jest to możliwe. Jednak transakcje nie są bezwarunkowo dobrą rzeczą. Jedynym sposobem na zapewnienie wykonania wszystkich operacji jest zgromadzenie razem wszystkich blokad. Transakcja zakłada wszystkie blokady, jakie nakłada aplikacja, ale nie zwalnia ich aż do pomyślnego zakończenia całego procesu. Ponieważ wiele blokad może być nałożonych i będą aktywne przez dłuższy okres czasu, niż gdyby były nakładane bez transakcji, wielodostępność aplikacji jest zmniejszona. Jednak baza danych jest łatwo dostępna, ale z niską integralnością danych nie jest zbyt dużo warta, więc transakcje wydają się być rozsądnym rozwiązaniem. Transakcje są realizowane przez metody obiektu Connection w ADO. W tabeli 21.6 opisane są te trzy metody. Tabela 21.6. Definiowanie transakcji Metoda Opis BeginTrans Od tego wywołania instrukcje będą wykonywane jak jedna. CommitTrans Kończy zestaw instrukcji i zatwierdza je do bazy danych. RollbackTrans W wypadku błędu anuluje wszystkie instrukcje i przywraca bazę danych do postaci sprzed BeginTrans. Podstawowa postać przetwarzania transakcyjnego przedstawiona jest na wydruku 21.1. Wydruk 21.1. Użycie transakcji w VBA Function TestTrans() As Boolean Dim conn As ADODB.Connection Dim rst As ADODB.Recordset On error resume Err_TestTrans Set conn=New ADODB.Connection Conn.BeginTrans ' wykonanie instrukcji np. instrukcji SQL lub metod Edit, Update ' AddNew ' Jeżeli wszystko się udało zatwierdzamy transakcję Conn.CommitTrans Exit Function Err_TestTrans: ' Coś poszło źle, anulujemy transakcję i przywracamy stan poprzedni Conn.RollbackTrans End Function Transakcje można zagnieżdżać, więc zatwierdzanie jednej transakcji zależy od zatwierdzenia innej. Gdy zagnieżdżamy transakcje, są one wykonywane od najniższego poziomu do najwyższego. Blokady Oracle/SQL Server Gdy oprzesz aplikację na serwerze SQL, np.: Oracle, Informix czy SQL Server, Access przestaje zarządzać blokadami. Jednak założenia pozostają identyczne – kontrolować dostęp do rekordów w taki sposób, aby wielu użytkowników mogło używać bazy w tym samym czasie. Serwery baz danych realizują to bardzo dobrze. Ponieważ dane są w tym samym miejscu co silnik bazy danych, blokowanie rekordów i zarządzanie wielodostępem realizowane jest szybko, niezauważalnie i stabilnie. Każdy z tych programów przechowuje informacje o blokadach w tabeli przechowywanej w pamięci i może efektywnie wykonać nałożenie blokady, wykonanie operacji i zdjęcie blokady w przeciągu mikrosekund. W przypadku użycia SQL Server używane są trzy typy blokad: ? Blokady współdzielone – używane są przy operacjach odczytu, pozwalają innym użytkownikom odczytać rekord lub stronę, która zawiera rekord. Na rekord lub stronę może być nałożone wiele blokad współdzielonych jednocześnie. Blokady te są zdejmowane zaraz po tym, jak dane przestają być potrzebne. ? Blokada na wyłączność – gdy wykonywane są instrukcje SQL Update, Delete lub Insert, na dane zakładana jest blokada na wyłączność. Jeżeli została nałożona blokada na wyłączność, nie można wykonać żadnej innej operacji nakładającej blokadę, dopóki serwer SQL zwolni blokadę po zatwierdzeniu danych. ? Blokada ruchoma – blokada ruchoma jest żądaniem blokady na wyłączność i jest nakładana po czterech kolejnych nieudanych próbach zablokowania rekordu na wyłączność. Blokada ruchoma nakładana jest również, gdy jednocześnie nałożonych jest zbyt wiele blokad współdzielonych. Gdy wystąpi taka sytuacja, serwer SQL nie nałoży więcej blokad współdzielonych. Blokady ruchome zabezpieczają przed zmonopolizowaniem tabeli przez blokady współdzielone (pochodzące z operacji odczytu) i niedopuszczeniem do operacji zapisu. Blokady ruchome zabezpieczają przed sytuacją zwaną jako „zagłodzenie blokadami”. Istnieją również inne strategie stosowane w SQL Server do zarządzania wielodostępnością. Między innymi: dynamiczne blokowanie rekordów (SQL Server 7.0), unikanie, wykrywanie i korygowanie zakleszczeń, kontrola blokowania optymistycznego i skalowalne narastanie blokad. Dynamiczne blokowanie rekordów polega na tym, że zarządca blokad dostosowuje konfigurację blokad serwera do wielkości używanej bazy danych. Powoduje to zmniejszenie zużycia zasobów oraz zmniejsza nakłady na ręczne zarządzanie blokadami na serwerze. Unikanie, wykrywanie i korygowanie zakleszczeń polega na tym, że SQL Server rozpoznaje sytuację, gdy dwa procesy pozostają ze sobą w konflikcie. W takiej sytuacji jedna transakcja blokuje dane potrzebne w drugiej oraz druga blokuje dane potrzebne w pierwszej transakcji. Pierwsza transakcja nie zwolni blokady, druga też tego nie zrobi. Bez interwencji silnika bazy transakcje te pozostaną zakleszczone. SQL Server wykrywa taką sytuację, odwołuje jedną z transakcji, kończy drugą i uruchamia pierwszą jeszcze raz, przełamując w ten sposób zakleszczenie. SQL Server aktywnie zapobiega zakleszczeniom, ograniczając ilość blokad tabel. SQL Server używa podejścia optymistycznego do zarządzania środowiskiem wielodostępnym. Przy użyciu tego podejścia użytkownicy mogą używać kursorów po stronie serwera do przeglądania danych w przód i w tył bez użycia blokad. Zamiast tego, SQL Server wykrywa zmiany rekordu i podejmuje stosowne działania (zwykle odrzuca zmiany, chyba że dane zostały jawnie zablokowane).Podejście takie powoduje, że ogromne ilości danych są dostępne dla użytkowników bez intensywnego zarządzania blokadami i związanych z tym narzutów. Rozdział 22. Replikacja i JRO W tym rozdziale: ? Kiedy użyć replikacji. ? Kiedy nie używać replikacji. ? Przystosowanie bazy do replikacji. ? Replikacja przy użyciu aktówki. ? Użycie interfejsu użytkownika. ? Jet i model obiektowy replikacji. ? Opis metod i właściwości JRO. ? Obiekty repliki. ? Kolekcja Filters. W czasach, gdy korporacje, coraz bardziej zależne od swoich danych, użytkownicy są coraz bardziej rozproszeni i żądają od swoich sieci coraz więcej. W odpowiedzi na to, tworzone są zdecentralizowane i rozproszone systemy, aby dostarczyć wszystkim informacji oraz rozładować obciążenie. Trend ten niesie z sobą nowe wyzwania. W jaki sposób korporacje mają zapewnić wszystkim dostęp do danych? Jak zagwarantować, że użytkownicy podejmą decyzje w oparciu o aktualne dane? Czy można zaufać danym? Jedną z technik spełniających te oczekiwania jest replikacja. Rozdział ten zajmuje się tworzeniem i zarządzaniem replikami. Opisany został nowy model obiektowy Jet Replication Model (JRO) używany do uruchomienia replikacji w aplikacjach i skorzystania z jej elastyczności. W silniku Jet zrobiono zauważalne ulepszenia procesu replikacji. Między innymi: dwukierunkową synchronizację z SQL Server, lepsze rozwiązywanie konfliktów, możliwość ustawiania priorytetów w schemacie bazy, rozdzielczość na poziomie kolumn oraz zakresy widoczności. Te usprawnienia pozwalają na lepszą kontrolę przy definiowaniu topologii replikacji. Kiedy użyć replikacji Istnieje kilka czynników, które powinny być wzięte pod uwagę przy rozważaniu użycia replikacji. Nie jest niespodzianką, że każdy potencjalny plus replikacji posiada także minus. Jednak istnieje kilka sytuacji, kiedy replikacja jest mądrym wyborem. Jeżeli wydajność aplikacji spada z powodu wielu konfliktów blokad, spowodowanych dużym ruchem w sieci lub częstym generowaniem raportów, można zauważyć, że podział bazy danych na dwie lub więcej replik i podział użytkowników pomiędzy nimi może usunąć problem blokad. Te dwa źródła danych wymienią się zmianami pomiędzy sobą. Podobnie, jeżeli każdy użytkownik potrzebuje tylko podzbioru danych w swojej bazie, częściowa replikacja może być odpowiednia, aby polepszyć wydajność, usunąć konflikty i zabezpieczyć ważne dane (przykładem może być aplikacja zarządzania działem kadr, która rozdziela zarządzanie pracownikami do kierowników poszczególnych działów i pozwala na dostęp do danych pracowników tylko własnego działu). Aby zwiększyć szybkość działania, aplikacja zarządzająca czasem pracy może dostarczyć repliki z historią czasu pracy każdego użytkownika. Co więcej, system taki dla programistów może zostać odłączony od sieci i zapisywać pracę wieczorem, w weekend lub u klienta. Schemat synchronizacji powinien rozwiązywać problemy napotkane w takiej aplikacji. Gdy ograniczasz zbiór danych, jaki może zobaczyć użytkownik, tworzysz w schemacie replikacji partycje. Może być to efektywną metodą zabezpieczenia rekordów przed zmianą przez nieuprawnione osoby. Istnieją trzy typy partycjonowania: pionowe, poziome i połączone poziome i pionowe. Gdy tworzy się partycję pionową, do osobnej bazy danych przeniesione zostaną tylko wybrane kolumny. Można to zrobić poprzez replikację przy użyciu kwerendy lub widoku, który ogranicza dane tylko do tych, które mają być udostępniane. Gdy replikujemy partycję pionową, musisz umieścić klucz główny w zapytaniu partycjonującym. Gdy tworzy się partycję poziomą, ograniczasz ilość rekordów do replikacji. Można to zrobić poprzez filtr replikacji lub poprzez kwerendę. Gdy replikujesz partycję poziomą, replikujesz całe rekordy. Partycjonowanie poziome i pionowe może zostać połączone, ograniczając zarówno wiersze jak i kolumny. Gdy aplikacja musi pracować bez przerwy, tworzenie kopii danych może spowodować niespodziewane przerwanie aplikacji. Replikacja może regularnie kopiować dane do repliki, która może być bezpiecznie archiwowana. Replikacja jest odpowiednim rozwiązaniem, gdy dane użytkownika są odporne na opóźnienia aktualizacji. Oznacza to, że użytkownicy mogą tolerować posiadanie przez jakiś czas nieaktualnych danych. Gdy raporty są wykonywane raz na godzinę lub raz dziennie, lub są oparte o dane do określonej godziny (np.: na koniec miesiąca, koniec roku podatkowego lub na koniec poprzedniego dnia), replikacja jest do zaakceptowania. Mimo że replikacja jest zwykle używana do rozprowadzania danych, może być użyta do rozprowadzania innych obiektów Accessa. Kiedyś użyłem replikacji, aby uaktualnić aplikację w Argentynie zmianami, których dokonałem w Nowym Jorku. Czasami replikacja może łagodzić niektóre problemy utrzymania aplikacji. Kiedy nie używać replikacji Jak wszystko inne, replikacja nie jest panaceum. Poniżej przedstawione zostały przypadki, kiedy nie powinieneś używać replikacji. Replikacja powoduje, że plik MDB jest dużo większy, ponieważ muszą zostać dodane dodatkowe obiekty, pola oraz dane niezbędne do uruchomienia i zarządzania repliką. Jeżeli system, na którym pracuje aplikacja, posiada mało wolnych zasobów, replikacja nie jest dobrym pomysłem. Obciążone systemy, które przeprowadzają wiele transakcji, mogą powodować problemy z replikacją. Duża częstotliwość transakcji i blokady zakładane w czasie tych transakcji zwykle prowadzą do konfliktów podczas synchronizacji danych. Rozwiązywanie tych konfliktów może bardzo obniżyć wydajność systemu. Bez efektywnego rozwiązywania problemów replikacja przyniesie aplikacji więcej kłopotów niż pożytku. Kiedy aktualność danych jest bardzo ważna, replikacja jest nie do zaakceptowania, ponieważ zakłada, że użytkownicy oddają aktualność danych w zamian za wydajność, współbieżność i mobilność. Przystosowanie bazy do replikacji Istnieje kilka sposobów na przystosowanie bazy danych do replikacji. W tym rozdziale opisane zostaną: aktówka, interfejs użytkownika Accessa oraz Jet Replication Object (JRO). Replikacja przy użyciu aktówki Najprostszą metodą replikacji danych jest użycie aktówki. Mimo że technika ta pozwala tylko na synchronizowanie komputera biurkowego z laptopem, jest dobrą metodą rozwiązania wielu problemów. Metoda ta działa także z innymi plikami, nie tylko z bazą Accessa. Można użyć replikacji przy użyciu aktówki dla siebie lub innych użytkowników, którzy chcą współdzielić pliki pomiędzy komputerem biurkowym i laptopem. Przed użyciem replikacji przy użyciu aktówki (lub każdej innej metody replikacji) upewnij się, że baza danych nie posiada hasła. Następnie należy wykonać następujące kroki: 94. Otwórz Explorer. 95. Otwórz aktówkę. 96. Skopiuj bazę danych Accessa do okna aktówki i wykonaj czynności zalecone w oknach dialogowych kończących się oknem z rysunku 22.1. Rysunek 22.1. Wybór bazy danych jako repliki w aktówce 97. W pierwszym oknie dialogowym kliknij przycisk Tak. Baza danych musi się zwiększyć, aby mogła być replikowana. 98. Pozwól aktówce wykonać kopię bazy danych, jeżeli masz odpowiednią ilość miejsca na dysku. 99. Jeżeli chcesz zmieniać tylko dane w bazie danych, w kolejnym oknie wybierz opcję niedopuszczania zmian struktury oryginalnej kopii bazy danych. Jeżeli spodziewasz się, że będziesz zmieniał projekt bazy, wybierz opcję Kopia aktówki. 100. Jeżeli otworzysz jedną z kopii, zauważysz w tytule okna Wzorzec projektowania lub Replika. 101. Skopiuj aktówkę na wymienny nośnik danych i zabierz ze sobą. Jednak, gdy komputery są połączone, przeciągnij aktówkę do innego komputera. 102. Gdy skończyłeś prace poza swoim komputerem, skopiuj zaktualizowany plik do komputera i po otwarciu aktówki wybierz Aktówka, Aktualizuj zaznaczenie. Aktówka stwierdza, jakie zmiany muszą być wykonane w każdym kierunku. Gdy sam używasz aktówki, jest prawie niemożliwe, abyś napotkał na konflikty w danych. W dalszej części rozdziału rozpatrzymy bardziej rozbudowane, drobiazgowe i potężne sposoby replikacji. Nie można odwrócić konwersji bazy w replikę, jednak można przywrócić bazę danych do niereplikowalnej formy. Aby to zrobić, wykonaj następujące kroki: 103. Z bazy danych, którą chcesz zmienić na formę niereplikowalną, wybierz Narzędzia, Opcje i zakładkę Widok. Wyłącz Obiekty systemowe. 104. Utwórz nową bazę danych i otwórz ją. 105. Zaimportuj wszystkie obiekty z repliki do nowej bazy. 106. Upewnij się, że na zakładce Widok w oknie dialogowym Opcje, wybrane jest pole wyboru Obiekty systemowe. 107. Usuń kolumny s_GUID, s_Lineage, s_Generation i s_colLineage z wszystkich tabel. 108. Zapisz nową bazę. Użycie interfejsu użytkownika Interfejs użytkownika Accessa pozwala na większą elastyczność niż aktówka, lecz jest nieco bardziej skomplikowany. Używając takiego podejścia, możesz uruchomić replikację pomiędzy różnymi użytkownikami w sieci, aby mogli współdzielić dane i inne obiekty Accessa. Gdy używamy interfejsu Accessa, można także wybrać, które z obiektów mają być replikowane i te, które nie będą replikowane. Podejście to pozwala na kontrolę, kiedy i z kim replikować. 109. Otwórz bazę na wyłączność, upewniając się, że nie ma założonego hasła. 110. Z menu Narzędzia wybierz Replikacja, Utwórz replikę (rysunek 22.2). Rysunek 22.2. Tworzenie repliki przez interfejs Accessa odbywa się przez wybór z menu 111. Access zamknie bazę i otworzy ją ponownie. Następnie Access zapyta o możliwość utworzenia kopii bazy. Kopia ma nazwę oryginalnej bazy danych i rozszerzenie BAK. Powinieneś pozwolić na utworzenie kopii. Proces konwersji może potrwać kilka minut, w zależności od stopnia skomplikowania bazy i ilości danych. W czasie procesu konwersji bazy do postaci repliki Access wykonuje następujące czynności: ? Tworzony jest nowy plik MDB i importowane są do niego wszystkie obiekty. ? Tworzy właściwość replicable dla każdego obiektu i ustawia jej wartość na T, więc zostanie on replikowany. ? Dodaje cztery pola o typach zamieszczonych w tabeli 22.1 do każdej tabeli w bazie danych. Tabela 22.1. Pola dodane do tabel w czasie ich przystosowania do replikacji Nazwa pola Typ pola Opis s_ColLineage OLE Object Śledzi zmiany w kolumnie lub polu s_Generation Number Śledzi zmiany rekordu s_Lineage OLE Object Śledzi inne zmiany s_GUID AutoNumber Globalny unikatowy identyfikator rekordu Pola te pozwalają na śledzenie przez Jet, zmian wprowadzonych do bazy danych i decydowanie o tym, co zrobić, gdy wystąpi konflikt pomiędzy dwoma bazami. Nie możesz zmieniać zawartości, typu danych lub nazw tych pól, normalnie nie są one widoczne w tabelach, chyba że zdecydujesz inaczej. Pola te zajmują trochę miejsca w bazie danych, w zależności od ilości danych oraz ilości obiektów w bazie, rozmiar plików rośnie od 10 do 100 procent. Jeżeli pole posiada typ Autonumerowanie, nie można oczekiwać, że replikacja będzie działać prawidłowo. Często stosuje się pole typu Autonumerowanie, o wartościach 1, 2, 3... Jedynym sposobem uniknięcia konfliktów jest zmiana typu danych przechowywanego w tym polu. Jeżeli pole ma typ Autonumerowanie z opcją Nowe wartości ustawioną na Przyrostowy, Jet zmienia tę opcję na Losowy, aby zmniejszyć prawdopodobieństwo konfliktu. Jeżeli ta zmiana okaże się niewystarczająca, można zmienić rozmiar takiego pola na ID Replikacji, co spowoduje nadanie każdego rekordu wartości GUID, który może być używany jako identyfikator rekordu. Tworzenie liczb losowych lub ID Replikacji jest wolniejsze niż zwiększenie wartości, ale czasami jest to konieczne i nieuniknione. Do bazy danych zostaje również dodanych kilka tabel. Tabele te mają prefiks MSys i jako takie mogą zostać zmienione przez Microsoft w kolejnych wersjach. Powinieneś poważnie się zastanowić przed napisaniem programu, który używa tych tabel. Są one używane przez Jet i tak powinno pozostać. W tabeli 22.2 opisane jest przeznaczenie tych tabel. Tabela 22.2. Tabele dodane do bazy danych podczas przystosowania do replikacji Nazwa tabeli Przeznaczenie MSysConflicts Zapamiętuje nierozwiązane konflikty. Tabela jest pusta po rozwiązaniu wszystkich konfliktów MSysExchangeLog Zapamiętuje różne dane na temat każdej synchronizacji MSysGenHistory Zapobiega wysłaniu niezmienionych rekordów w trakcie synchronizacji MSysOthersHistory Zapisuje różne szczegóły działania z innych replik Tabela 22.2. Tabele dodane do bazy danych podczas przystosowania do replikacji (ciąg dalszy) Nazwa tabeli Przeznaczenie MSysRepInfo Informacje o zbiorze replik i wzorcu projektowania, razem z GUID MSysReplicas GUID dla każdej repliki w zbiorze MSysRepLock Zapisuje nieudane próby zablokowania rekordów w trakcie synchronizacji MSysSchChange Zmiany schematu bazy danych wykonane we wzorcu projektowania. Są tu przechowywane, dopóki są potrzebne MSysSchedule Zapisy planowania tworzone przez Replication Manager MSysSideTables Nazwy tabel i GUID dla potrzeb konfliktów MSysTableGuids Nazwy replikowanych tabel wraz z GUID MSysTombStone GUID tabel i rekordów dla usuniętych obiektów MSysTranspAddress Identyfikuje replikę (repliki), z którą bieżąca replika jest synchronizowana Tabele te są tylko do odczytu, a niektóre dane są przechowywane jako obiekty OLE, więc nie mogą być wyświetlane. Dodatkowo do bazy danych dodanych zostaje kilka właściwości, aby można było sprawować kontrolę nad replikacją. Właściwości te to: Replicable, ReplicableID oraz DesignMasterID. ? Replicable wskazuje silnikowi Jet, że baza może być replikowana. ? ReplicableID w sposób jednoznaczny identyfikuje bazę danych i wyróżnia ją spośród innych replik. ? DesignMasterID wskazuje na bazę, która zarządza zmianami w replikach. Zmiany w projekcie można wprowadzać tylko do źródła projektowania. Powinna istnieć tylko jedna baza danych wskazana jako źródło projektowania w schemacie replikacji lub zbiorze replik. Posiadanie więcej niż jednego źródła projektowania prowadzi do uszkodzenia i utraty danych. Niektóre obiekty są potrzebne tylko przez lokalną aplikację, więc powinieneś zauważyć, że szablony, większość tabel systemowych i kreatorzy nie są replikowani. Jednak tabele systemowe biorące udział w śledzeniu procesu replikacji są replikowane, a MsysAccessObjects oraz MsysCmdBars są również replikowane, co powoduje, że schemat bazy danych oraz menu mogą być częścią schematu replikacji. Replikacja ogranicza ilość zagnieżdżonych transakcji w bazie. Replika obsługuje tylko sześć zagnieżdżonych transakcji. Wybór między obiektami lokalnymi i replikowanymi Gdy rezygnujesz z używania aktówki jako narzędzia replikacji i rozpoczynasz korzystanie z możliwości Accessa, jedną z pierwszych rzeczy, nad którą powinieneś się zastanowić, jest wybór czy obiekt ma być lokalny, czy replikowany. Kolejnymi są: wybór topologii replikacji oraz czy proces replikacji ma być kierowany, czy niekierowany, bezpośredni lub pośredni. Domyślnie Access zaznacza wszystkie obiekty do replikacji. Zwykle jednak aplikacja posiada obiekty, które nie muszą być replikowane. Mogą to być tabele zawierające ustawienia lokalne, tabele tymczasowe lub proste kwerendy, które nie będą zmieniane (przykładowo Select * from Customers Order by CompanyName). Możesz kontrolować, które obiekty będą zmieniane w trakcie synchronizacji poprzez ustawienie właściwości Replicable. Jeżeli obiekt jest replikowany, właściwość posiada zaznaczone pole wyboru w oknie właściwości obiektu, gdy jest lokalny – pole jest wyczyszczone i obiekt nie będzie synchronizowany. Aby zmienić obiekt na lokalny, należy wykonać poniższe kroki: 112. Wybierz obiekt. 113. Kliknij prawym klawiszem myszy i wybierz Właściwości z menu kontekstowego. 114. Wyczyść pole wyboru przy właściwości Replicable i kliknij OK. Wzorzec projektowania, na którym obecnie pracujesz, jest specjalną bazą danych. Jest ona jedyna, na której możesz dokonywać zmian i zmiany te zostaną przeniesione do replik. Zwykle wzorzec projektowania nie synchronizuje się z replikami, ponieważ użytkownicy mogliby dostać niegotowy program. Dobrze jest izolować wzorzec od zbioru replik do czasu, gdy chcesz rozesłać zmiany, jakie zrobiłeś w bazie danych. Aby utworzyć topologię replikacji, powinieneś utworzyć odpowiednią ilość replik z właśnie stworzonej repliki. Nie twórz kolejnych replik z oryginalnej bazy danych, ponieważ zostanie utworzonych wiele wzorców projektowania, co może utrudnić życie. Wszystkie repliki utworzone z tej repliki, lub z repliki tej repliki, będą członkami tego samego zbioru replik. Posiadają one wspólny zestaw numerów GUID, co pozwala im na wymianę danych i informacji o schemacie bazy. Kolejność, w jakiej tworzyłeś repliki, ma mały wpływ na kolejność replikacji. Każda replika może synchronizować się z każdym członkiem zbioru, a Ty masz możliwość kontrolowania kolejności replikacji. W czasie synchronizacji możesz wybrać replikę lub repliki, z którymi chcesz wymienić dane. Jak pokazane jest na rysunku 22.2, w Accessie można to zrobić poprzez menu Narzędzia, Replikacja, Synchronizuj. Domyślnym ustawieniem jest wybór jednej repliki, z którą ma być wykonana synchronizacja, jednak masz do wyboru również inne opcje. Masz możliwość wyboru replikacji w tle z każdą repliką, do której masz w danej chwili dostęp, lub z jedną repliką. Planowanie topologii replikacji Decyzja użycia replikacji i utworzenie replik to tylko część tego, co należy zrobić, aby wykorzystać możliwości replikacji Accessa. Następnie musisz ustalić, kto będzie z kim synchronizował dane, kiedy będzie je synchronizował, jak zapewnić, że replikacja będzie wykonana na czas oraz jak obsługiwać zawiłości takie jak zdalni użytkownicy i powolne połączenia. Zagadnienia te powinny być rozważone w czasie projektowania topologii replikacji lub mapy replik. Mapa taka określa miejsce, gdzie znajduje się replika, w jakiej relacji pozostają ze sobą repliki, w jaki sposób tworzona jest replika i kiedy następuje. Topologia replikacji jest kluczowa dla wydajności i pewności działania. Powinieneś dokładnie przemyśleć różne dostępne topologie i wybrać tę, która najbardziej odpowiada Twoim wymaganiom. Nie pozwól, by wyborem topologii rządził przypadek. Ilość kombinacji możliwych topologii jest niemal nieograniczona, gdy uwzględnisz możliwość synchronizacji w jednym lub dwóch kierunkach. Możesz wymusić na jednej replice zbieranie wszystkich zmian z replik i nieprzekazywanie ich dalej. Może być to użyteczne do efektywnego dostarczania wyników pracy dnia do komputera kierownika, a kierownik raportuje i analizuje dane bez dokonywania żadnych zmian. Replikacja może następować według tradycyjnego modelu, gdzie dwie bazy synchronizują ze sobą dane, aby obie zawierały wszystkie zmiany zrobione w obu bazach. Rysunek 22.3 pokazuje kilka możliwych topologii replikacji. Zwróć uwagę na zależności i przepływ danych. W sieci lokalnej (LAN), użytkownicy mogą utrzymywać przez większość czasu stałe połączenia z innymi użytkownikami. W takim wypadku gwiazda, pętla, wielokrotne połączenia, magistrala oraz drzewo będą dobrze działać. Każda z tych topologii ma swoje zalety i wady. Wybrana przez Ciebie topologia powinna być kombinacją tych bazowych typów. W tabeli 22.3 zostały opisane niektóre wady i zalety podstawowych typów. Tabela 22.3. Wady i zalety różnych topologii Topologia Zalety Wady Zalecane użycie Wielokrotne połączenia Zapewnienie najbardziej aktualnych danych Możliwe duże obciążenie sieci Gdy ważne są szybkie aktualizacje i jest niewielu użytkowników Gwiazda Małe obciążenie sieci Środek jest newralgicznym punktem, obciążenie jest nierównomierne, wymagane są wielokrotne synchronizacje, aby rozesłać zmiany do wszystkich użytkowników Niewielu użytkowników i powolna sieć Rysunek 22.3. Podstawowe topologie replikacji Tabela 22.3. Wady i zalety różnych topologii (ciąg dalszy) Topologia Zalety Wady Zalecane użycie Drzewo Małe obciążenie, dokładna kontrola nad zależnymi replikami Nieoczywiste opóźnienia, nierówne obciążenie, uszkodzenie niektórych węzłów jest poważniejsze niż innych Gdy tylko niektórzy użytkownicy uaktualniają dane, drzewo jest bardzo efektywne Pętla Równe rozłożenie obciążenia, małe obciążenie sieci Nieodporna na uszkodzenia, jeżeli replikacja nie może odwrócić kierunku Użyj w sytuacjach, gdy ważne jest równe obciążenie Magistrala Największe opóźnienie, równe rozłożenie obciążenia, małe obciążenie sieci Bardzo nieodporna na uszkodzenia Proste tworzenie, dobre tylko dla replikacji pojedynczego użytkownika W sieciach rozległych, gdzie utrzymanie stałego połączenia nie jest możliwe lub jest ono zbyt wolne, topologie te mogą być łączone poprzez przypisanie jednej z replik roli odległej repliki dla innej topologii lub podsieci. Jet może synchronizować bazy poprzez Internet lub Intranet. Niezależnie czy używasz interfejsu Accessa do implementacji replikacji, czy używasz JRO lub DAO, powinny zostać rozważone wszystkie topologie przed wybraniem właściwego rozwiązania, bazowanego na ich wadach i zaletach oraz potrzebach aplikacji. Niezależnie od podejścia, jakiego używasz do implementacji replikacji, jesteś jedynym, kto może spowodować, że replikacja będzie miała miejsce. W przypadku prostego schematu możesz użyć okna z menu Narzędzia, Replikacja, Synchronizuj lub przez wywołanie synchronizacji poprzez zdarzenie w aplikacji. Zdarzenie może być wykonywane podczas uruchamiania aplikacji, w regularnych odstępach czasu (można użyć stopera na niewidocznym formularzu) lub po określonej liczbie wykonanych zmian. W trakcie synchronizacji, musisz wybrać pomiędzy schematem sterowanym i niesterowanym. Jeżeli zdecydujesz się na użycie schematu sterowanego, możesz także zdecydować, czy replikacja ma być bezpośrednia czy pośrednia. Twoje rozwiązanie może używać różnych ustawień w różnych miejscach, lecz jest bardzo ważne, aby wiedzieć, co one znaczą. Wybór schematu sterowanego Schemat sterowany używa aplikacji Manager replikacji oraz Manager synchronizacji. Manager replikacji pozwala na planowanie i kontrolę replikacji oraz rozwiązywanie powstałych konfliktów. Możliwość pracy w tle, przechowywanie rekordów oraz synchronizacja co 15 minut powoduje, że warto jej używać. Mimo że istnieje możliwość skopiowania takich funkcji we własnym programie JRO lub DAO, zwykle nie ma takiej potrzeby. Synchronizacja bezpośrednia Bezpośrednia synchronizacja zachodzi, kiedy obie bazy danych są jednocześnie otwarte i uaktualniane. Aby niezawodnie wykonać bezpośrednią synchronizację, powinieneś mieć pewne i stałe połączenie pomiędzy replikami. Synchronizacja pośrednia Powinieneś używać synchronizacji pośredniej dla połączeń poprzez WAN lub dla wolnych połączeń. W czasie synchronizacji pośredniej jedna baza jest otwierana, a pakiet zmian jest wysyłany do Managera synchronizacji. Gdy wszystkie pakiety zmian zostaną dostarczone, pierwsza baza danych jest zamykana a druga jest otwierana i aktualizowana. Taka operacja jest mniej podatna na przerwanie połączenia. Wybór schematu niesterowanego Schemat niesterowany nie polega na Managerze synchronizacji. Jeżeli masz bardzo poważne powody, jak na przykład częstsza synchronizacja, niż pozwala na to manager lub niektóre typy synchronizacji zależnej od zdarzeń (np. gdy ilość przedmiotów w magazynie przekroczy założony poziom), możesz sterować synchronizacją za pomocą własnego programu. Po tych wyjaśnieniach wybierz Narzędzia, Replikacja, Synchronizuj i kliknij przycisk OK, aby rozpocząć synchronizację poprzez interfejs użytkownika Accessa. Jet i model obiektowy replikacji Najlepszą kontrolę nad procesem replikacji oraz rozwiązywaniem konfliktów zapewnia użycie obiektów z Jet Replication Object (JRO). Przy użyciu tej metody jest możliwe prawie całkowite ukrycie przed użytkownikami procesu replikacji. Jeżeli dokładnie zaplanuje się proces replikacji, JRO pozwoli na skorzystanie ze współdzielonych danych w sposób bezbolesny i niewidoczny dla użytkowników aplikacji. Gdy będziesz programował funkcje replikacji, możesz wybrać pomiędzy dwoma modelami obiektowymi, które mają różne możliwości oraz inny interfejs. Można skorzystać z Data Access Objects (DAO) lub nowego Jet Replication Object. W DAO możliwość replikacji danych jest wbudowana w obiekty razem z funkcjami manipulacji danych, bezpieczeństwa i definiowania struktur danych. Jeżeli używasz do przetwarzania danych ADO (domyślne dla Accessa 2000), to nie ma powodu ładować dużej biblioteki DAO (DAO360.dll ma wielkość 541 kB) duplikującej istniejące możliwości, jeżeli nie potrzebujesz ich w całości. Zamiast tego użyj specjalizowanej i rozszerzonej biblioteki JRO (MSJRO.dll ma 97 kB). W rozdziale tym przedstawimy sposób obsługi replikacji przy użyciu JRO. Jet Replication Object jest interfejsem dla replikacji oraz podstawowej konserwacji w silniku bazy danych Jet. W rozdziale tym przedstawimy tyko replikację pomiędzy bazami danych obsługiwanymi przez Jet, mimo że można używać JRO do zaprogramowania replikacji pomiędzy SQL 7.0 i Jet 4.0. Tak jak ADO, ADOR i ADOX, JRO podąża za trendem spłaszczania struktury modelu obiektowego. Model posiada tylko kilka warstw, więc metody i właściwości są łatwo dostępne z poziomu obiektu. Rysunek 22.4 ilustruje model JRO. Rysunek 22.4. Model JRO Poznajemy JRO JRO udostępnia zestaw metod i właściwości pozwalający kontrolować możliwości replikacji Accessa. W tej części rozdziału objaśnione zostaną części modelu obiektowego. W tabelach 22.4 oraz 22.5 znajdują się właściwości i metody obiektu Replica. Tabela 22.4. Właściwości JRO.Replica Nazwa Składnik klasy Typ Uwagi ActiveConnection JRO.Replica Object ConflictFunction JRO.Replica String ConflictTables JRO.Replica Recordset Tylko do odczytu DesignMasterID JRO.Replica Variant Priority JRO.Replica Long Tylko do odczytu ReplicaID JRO.Replica Variant Tylko do odczytu ReplicaType JRO.Replica RepIicaTypeEnum Tylko do odczytu RetentionPeriod JRO.Replica Long Visibility JRO.Replica VisibilityEnum Tylko do odczytu Tabela 22.5. Metody JRO.Replica Metoda Składnia CreateReplica Replica.CreateReplica(NazwaRepliki, Opis [,TypRepliki] [,Widoczność] [,Priorytet] [,Aktualizacja]) Tabela 22.5. Metody JRO.Replica (ciąg dalszy) Metoda Składnia GetObjectReplicability Set ReturnValue = Replica.GetObjectReplicability (NazwaObiektu, TypObiektu) MakeReplicable Replica.MakeReplicable([CiągPołączenia] [,Śledzenie kolumn]) PopulatePartial Replica.PopulatePartial(PełnaReplika) SetObjectReplicability Replica.SetObjectReplicability(NazwaObiektu, TypObiektu, Replikowalność) Synchronize Replica.Synchronize(Cel [,TypSynchronizacji] (,TrybSynchronizacji]) Tabele 22.6 i 22.7 zawierają właściwości i metody kolekcji JRO.Filters. Tabela 22.6. Właściwości kolekcji JRO.Filters Nazwa Składnik klasy Typ Uwagi Count JRO.Filters Long Tylko do odczytu Item JRO.Filters Filter Tylko do odczytu Właściwość domyślna Tabela 22.7. Metody kolekcji JRO.Filters Metoda Składnia Append Filters.Append(NazwaTabeli [, TypFiltra], KryteriaFiltra) Delete Filters.Delete(Indeks) Refresh Filters.Refresh Tabela 22.8 zawiera właściwości JRO.Filter. Tabela 22.8. Właściwości JRO.Filter Nazwa Składnik klasy Typ Uwagi FilterCriteria JRO.Filter String Tylko do odczytu FilterType JRO.Filter Enum Tylko do odczytu TableName JRO.Filter String Tylko do odczytu Opis metod i właściwości JRO Jet Replication Object zawiera do swojego użytku kilka metod i właściwości. Właściwości są używane do identyfikacji bazy danych, umieszczenia jej w Twojej topologii replikacji oraz wyznaczają sposób obsługi konfliktów. Metody zajmują się tworzeniem replik, synchronizacją między replikami oraz określają, które informacje są przesyłane pomiędzy replikami. Obiekt JRO Replica zawiera również kolekcję filtrów, które ograniczają poprzez zdefiniowane warunki, dane przesyłane pomiędzy replikami. Właściwość ActiveConnection ActiveConnection jest obiektem Connection, należącym do repliki. Właściwość ta może być poprawnym ciągiem połączeniowym, jeżeli obiekt Connection jest niedostępny. Tak jak w całym ADO, jeżeli właściwość ActiveConnection ma wartość Nothing, wszystkie zależne obiekty są odłączone od źródła danych. Właściwość ConflictFunction Jako wartość właściwości ConflictFunction można przypisać nazwę własnej funkcji rozwiązywania konfliktów synchronizacji. Można utworzyć własną funkcję rozwiązywania konfliktów, jeżeli domyślna działa w sposób, który Ci nie odpowiada. We wcześniejszych wersjach Jet występowały błędy replikacji (błędy powtórzenia klucza, naruszenie więzów integralności, problemy kontroli poprawności itd.) oraz konflikty replikacji (dwoje użytkowników wprowadziło zmiany pozostające w konflikcie) i każda z tych sytuacji obsługiwana była oddzielnie. W Jet 4.0 błędy replikacji i konflikty replikacji są traktowane jednolicie. Pozwala to na łatwiejsze rozwiązywanie problemów replikacji. W czasie tworzenia schematu replikacji powinieneś spodziewać się następujących typów konfliktów: ? Jednoczesne zmiany. Dwóch użytkowników zmieniało ten sam rekord w tym samym czasie. Jeden z użytkowników straci swoje zmiany, a jego rekord przesłany zostanie do tabeli konfliktów. ? Błąd powtórzenia klucza. W czasie synchronizacji dwa rekordy mają taką samą wartość w polu klucza. ? Naruszenie poprawności wartości w tabeli. W czasie synchronizacji rekord narusza zasady poprawności danych zapisane podczas tworzenia projektu tabeli (puste ciągi znaków, wartości poza zakresem itp.). Gdy wystąpi naruszenie reguł poprawności, rekord jest odrzucany. ? Naruszenie więzów integralności. Gdy usunięty zostanie rekord w replice, który jest jedną ze stron relacji jeden do wielu, wszystkie rekordy bazujące na kluczu obcym zostaną w trakcie synchronizacji odrzucone. Gdy zmieniamy klucz główny rekordu w replice, zmiana klucza spowoduje, że rekordy bazujące na poprzedniej wartości klucza w innych replikach zostaną odrzucone. Rekordy repliki z kluczem obcym bazującym na nieprawidłowej wartości klucza głównego również zostaną odrzucone. W każdym z tych przypadków kreator rozwiązywania konfliktów pokaże użytkownikowi odrzucony rekord. Użytkownik może zdecydować, czy powtórnie wykonać zmiany, anulować zmiany lub zmienić dane powodujące konflikt. Access używa wbudowanej procedury rozwiązywania konfliktów. Kreator rozwiązywania konfliktów pokazuje użytkownikowi każdy konflikt i musi on zadecydować, który rekord zawiera prawidłowe dane. Aby uniknąć tego procesu, można użyć właściwości ConflictFunction. Pozwala ona na użycie własnej procedury rozwiązywania konfliktów, które wystąpiły w czasie synchronizacji lub może wskazać replikę, której rekordy są zawsze najważniejsze w wypadku wystąpienia konfliktu. Jako wartość właściwości ConflictFunction należy przypisać nazwę funkcji, która ma być wywołana w wypadku konfliktu. Musi być to nazwa funkcji, nie można podać nazwy procedury. Jeżeli właściwość ta nie jest ustawiona, Access wywoła wbudowaną funkcję rozwiązywania konfliktów. Funkcja rozwiązywania konfliktów jest wywoływana po zakończeniu synchronizacji. Gdy tworzymy funkcję rozwiązywania konfliktów, operujemy na zawartości tablicy konfliktów w Twojej replice, aby ocenić konflikt oraz zmienić rekord lub zbiór rekordów przy użyciu zwykłych mechanizmów manipulacji danymi (DAO, ADO, RDO lub SQL). Gdy wprowadzasz własną procedurę rozwiązywania konfliktów, zastępujesz nią wbudowany algorytm rozwiązywania konfliktów. Powinieneś dokładnie rozważyć sytuacje, w których jest to potrzebne. Jedną z możliwych sytuacji, kiedy możesz skorzystać z napisania własnej funkcji rozwiązywania konfliktów jest to gdy chcesz sprawdzić przynależność użytkownika do grupy, aby zdecydować, czy jego zmiany mają pierwszeństwo przed zmianami innego użytkownika. Podejście takie pozwala na pracę użytkownika na różnych replikach bez względu na priorytet danej repliki w topologii replikacji. Domyślnie Jet 4.0 rozwiązuje konflikty przy użyciu dwóch algorytmów bazujących na priorytetach oraz unika konfliktów przez ich poszukiwanie tylko na poziomie kolumn. W Jet 4.0 każdej replice jest przypisana wartość priorytetu. Ta liczba wyznacza miejsce repliki w topologii. Jeżeli dwie repliki spowodowały konflikt, Jet rozwiązuje go, bazując na ich relacjach w topologii. Zmiany repliki o wyższym priorytecie są ważniejsze. W wypadku remisu ważniejsza jest replika z mniejszą wartością ReplicaID (replika utworzona wcześniej). Algorytm ten jest zbliżony do używanego w SQL Server 7.0. Wartość priorytetu przyjmuje wartości od 0 do 100. W trakcie tworzenia repliki otrzymuje priorytet równy 90% wartości źródła. W Jet 4.0 konflikty powinny wystąpić rzadziej niż we wcześniejszych wersjach. We wcześniejszych wersjach występował konflikt, gdy dwóch użytkowników zmienia to ten sam rekord, nawet, gdy zmienili dane w różnych polach. W Jet 4.0 dwóch użytkowników może zmienić różne pola tego samego rekordu i konflikt nie nastąpi. Śledzenie zmian na poziomie kolumn radykalnie redukuje częstość konfliktów i odciąża użytkowników od rozwiązywania tych konfliktów. Śledzenie zmian na poziomie kolumn jest domyślnie włączone w Jet 4.0. Jeżeli Twoja aplikacja potrzebuje śledzenia zmian na poziomie rekordów, opcja musi być zmieniona przed przystosowaniem tabel do replikacji. Aby wybrać pomiędzy śledzeniem zmian na poziomie kolumn i rekordów, użyj parametru columntracking metody replica.MakeReplicable. Ustawienie tego argumentu na True włącza śledzenie zmian na poziomie kolumn, a False włącza śledzenie zmian na poziomie rekordów. Poniższa metoda powinna przystosować bazę do replikacji ze śledzeniem zmian na poziomie rekordów: Replica.MakeReplicable CurrentProject.Connection, False Właściwość ConflictTables Właściwość ta wskazuje na obiekt RecordSet zawierający listę tabel i skojarzonych z nimi tabel konfliktów. Wywołanie właściwości ConflictTables zwraca RecordSet zawierający dwie kolumny: TableName i związaną z nią ConflictTableName. Dla każdej tabeli z konfliktami istnieje tabela przechowująca rekordy powodujące konflikty. Właściwość ConflictTables można tylko odczytywać. Otwierając tabelę o nazwie podanej w polu ConflictTableName właściwości ConflictTables, można obejrzeć rekord stracony przy synchronizacji oraz obejrzeć jego pola specyficzne dla replikacji. Na wydruku 22.1 pokazany jest przykład prostej funkcji rozwiązywania konfliktów. Używa on ADO, ADOX i JRO do przetworzenia wszystkich konfliktów przy użyciu właściwości ConflictTables. Wydruk 22.1. Proste rozwiązywanie konfliktów Function CustomDataConflictResolver() Dim jro As New jro.Replica Dim cat As New ADOX.Catalog Dim conflrs As New Recordset Dim rs As New Recordset On Error Goto CustomDataConflictResolver Error Set jro.ActiveConnection = CurrentProject.Connection Set cat.ActiveConnection = CurrentProject.Connection ' jro.ConflictTables zwraca Recordset z nazwami tabelami ' zawierających konflikty Set conflrs = jro.ConflictTables ' Dla każdej związanej tablicy konfliktów rozpoznaj konflikt ' i rozwiąż go While Not conflrs.EOF ' Otwórz tabelę aktualnego konfliktu i analizuj utracony rekord rs.Open "Select * From " & conflrs.Fields(1), jro.ActiveConnection While Not rs.EOF ' Oceń tutaj rekordy pozostające w konflikcie i ' użyj SQL lub ADO, aby zapisać właściwe zmiany ' Upewnij się, że zachowałeś rekordy, w których nie rozwiązałeś ' konfliktu rs.MoveNext Wend ' Zamknij recordset z utraconymi rekordami rs.Close ' Pobierz nazwę następnej tabeli conflrs.MoveNext Wend ' Gdy tworzysz własną funkcję rozwiązywania konfliktów ' musisz usunąć zawartość tabeli konfliktów While Not conflrs.EOF cat.Tables.Delete (conflrs.Fields(1)) conflrs.MoveNext Wend CustomDataConflictResolver = True CustomDataConflictResolver _Exit: conflrs = Nothing rs = Nothing jro = Nothing Exit Function CustomDataConflictResolver Error: ' Obsługa błędów CustomDataConflictResolver = False Resume CustomDataConflictResolver _Exit End Function Sposób, w jaki rozwiążesz konflikty, należy całkowicie do ciebie. Możesz brać zawsze ostatni rekord, zawsze rekord z określonej grupy lub określonego użytkownika, pobierać rekord w oparciu o największą lub najmniejszą wartość albo użyć kombinacji wszystkich tych sposobów. Właściwość DesignMasterID Wartość DesignMasterID jest identyfikatorem GUID, który określa wzorzec projektowania w zbiorze replik. Właściwość ta jest ustawiana w trakcie tworzenia wzorca projektowania. Możesz zmienić replikę we wzorzec projektowania, gdy oryginalny wzorzec zostanie stracony, jednak replika nie może zmienić innej repliki we wzorzec projektowania. Ustawienie tej właściwości w replice, jeżeli w tym zbiorze replik istnieje wzorzec projektowania, może podzielić zbiór na dwa niezgodne zbiory replik. Jeżeli się to zdarzy, nie będziesz mógł wykonać synchronizacji z wszystkimi dotychczasowymi użytkownikami. Ponieważ GUID wzorca projektowania jest globalnie unikatowy, konwertuj replikę na wzorzec projektowania tylko w nadzwyczajnych sytuacjach, kiedy wzorzec projektowania został stracony lub uszkodzony i nie istnieje inny wzorzec projektowania. Obiekty repliki Każda baza danych utworzona z wzorca projektowania lub innej repliki jest obiektem Replica dostępnym poprzez JRO. Poniższe właściwości i metody pozwalają rozróżnić repliki i kontrolować ich zachowanie i współpracę z innymi replikami. Właściwość ReplicaID Właściwość ta w sposób jednoznaczny identyfikuje bazę danych repliki i zawiera GUID typu Variant. Wartość GUID jest tworzona razem z repliką i jest możliwy tylko jej odczyt. Właściwość ReplicaType Właściwość ta wskazuje na typ repliki. Właściwość ta zawiera jedną ze stałych wymienionych w tabeli 22.9. Tabela 22.9. Wartości ReplicaType Stała Wartość Opis jrRepTypeNotReplicable 0 Domyślna. Baza danych nie jest replikowana jrRepTypeDesignMaster 1 Replika jest wzorcem projektowania jrRepTypeFull 2 Replika jest pełną repliką jrRepTypePartial 3 Replika jest repliką częściową Właściwość ReplicaType (tylko do odczytu) wskazuje na to, czy baza jest replikowana a jeżeli jest, w jaki sposób jest replikowana. Jeżeli ReplicaType ma wartość jrRepTypeNotReplicable, baza nie była przygotowywana do replikacji. Można użyć parametru ReplicaType metody CreateReplica, aby utworzyć pełną lub częściową replikę. Właściwość RetentionPeriod Właściwość ta wskazuje, ile dni (od 5 do 32000) przechowywać historię replikacji. Historia zawiera szczegóły o usuniętych rekordach, zmianach projektu oraz inne specyficzne dla systemu informacje. Jeżeli baza danych została przygotowana do replikacji poprzez ADO, RDO lub manager replikacji, domyślną wartością jest 60 dni. Jeżeli baza została przygotowana do replikacji poprzez interfejs użytkownika Accessa, wartością domyślną jest 1000 dni. Właściwość ta musi być ustawiana we wzorcu projektowania. Właściwość Visibility Właściwość Visibility wskazuje na to, czy replika jest globalna, lokalna lub anonimowa. Visibility zarządza oddziaływaniem pomiędzy replikami i zawiera jedną ze stałych wymienionych w tabeli 22.10. Tabela 22.10. Możliwe wartości właściwości Visibility Stała Wartość Opis jrRepVisibilityGlobal 1 Domyślna. Replika globalna jrRepVisibilityLocal 2 Replika lokalna jrRepVisibilityAnon 4 Replika anonimowa Z repliki globalnej można utworzyć replikę dowolnego typu. Wszystkie zmiany w globalnej replice są śledzone i mogą być wymieniane z każdą globalną repliką w zbiorze. Globalna replika może również wymieniać zmiany z każdą lokalną lub anonimową repliką, które przynależą do jednego węzła. Lokalne i anonimowe repliki wymagają globalnej repliki, która będzie węzłem w ich topologii. Nie mogą synchronizować się z innymi replikami w tym zbiorze replik. Wszystkie anonimowe i lokalne repliki mają priorytet 0, więc zawsze przegrywają przy rozwiązywaniu konfliktów z węzłem. Tylko replika będąca węzłem „wie” o istnieniu lokalnych replik i tylko ona może zaplanować replikację z lokalnych replik. Repliki anonimowe mogą być używane w topologii internetowej, gdzie dane są silnie rozproszone, ponieważ nie są utrzymywane informacje systemowe, przez co rozmiar repliki jest silnie zmniejszony. Żadna replika, nawet replika będąca węzłem nie może nawiązać połączenia z repliką anonimową. Replika węzłowa nie może zaplanować replikacji z repliką anonimową. Visibility jest właściwością niezmienną i nie może być zmieniana po utworzeniu repliki przy użyciu metody CreateReplica. Metoda CreateReplica Metoda ta tworzy nową replikę na podstawie bieżącej replikowalnej bazy danych. Replica.CreateReplica(NazwaRepliki, Opis [,TypRepliki] [,Widoczność] [,Priorytet] [,Aktualizacja]) NazwaRepliki – ciąg przechowujący pełną ścieżkę dostępu do tworzonej repliki. Opis – ciąg opisujący tworzoną replikę. TypRepliki – parametr opcjonalny. Typ tworzonej repliki. Wartością domyślną jest jrRepTypeFull. Gdy tworzona jest pełna replika, w trakcie synchronizacji wymieniane są wszystkie dane. W częściowej replice wymieniane są tylko dane spełniające warunki filtra. Prawidłowe wartości stałych dla tego parametru opisane są w tabeli 22.11. Tabela 22.11. Możliwe wartości parametru TypRepliki Stała Wartość Opis jrRepTypeNotReplicable 0 Domyślna. Baza danych nie jest replikowana jrRepTypeDesignMaster 1 Replika jest wzorcem projektowania jrRepTypeFull 2 Replika jest pełną repliką jrRepTypePartial 3 Replika jest repliką częściową Widoczność – parametr opcjonalny. Wartość tego parametru określa widoczność repliki. Wartością domyślną jest jrRepVisibilityGlobal. Prawidłowe wartości stałych dla tego parametru opisane są w tabeli 22.12. Tabela 22.12. Możliwe wartości parametru Widoczność Stała Wartość Opis jrRepVisibilityGlobal 1 Domyślna. Replika globalna jrRepVisibilityLocal 2 Replika lokalna jrRepVisibilityAnon 4 Replika anonimowa Priorytet – parametr opcjonalny. Jest to wartość typu Long, która wskazuje, która replika wygrywa w trakcie rozwiązywania konfliktów. Domyślną wartością jest -1, co oznacza, że baza danych powinna ustalić właściwą wartość. Gdy tworzysz globalne repliki, ich domyślny priorytet jest ustawiany na 90% wartości priorytetu repliki źródłowej. Jeżeli jesteś administratorem bazy, możesz ustawić dowolną wartość od 0 do 100. Repliki lokalne i anonimowe zawsze mają priorytet 0 i nie może być on zmieniany. Wartość ta jest wymuszana podczas tworzenia repliki i próby jej zmiany są ignorowane. Aktualizacja – parametr opcjonalny. Wartość parametru określa, czy możliwe są zmiany w replice. Domyślną wartością jest jrRepUpdFull. Stała jrRepUpdReadOnly uniemożliwia użytkownikom wprowadzanie zmian do replikowanych tabel. Jednak, gdy synchronizujesz nową replikę z inną ze zbioru replik, zmiany struktury i danych są przenoszone do nowej repliki. W tabeli 22.13 wymienione są stałe dopuszczalne dla parametru Aktualizacja. Tabela 22.13. Możliwe wartości parametru Stała Wartość Opis jrRepUpdFull 0 Replika może być zmieniana jrRepUpdReadOnly 2 Replika nie może być zmieniana Replika dziedziczy dokładnie taką samą charakterystykę lub jest bardziej restrykcyjna od repliki, na podstawie której została utworzona. Przykładowo, na podstawie globalnej repliki tylko do odczytu, można utworzyć lokalną lub anonimową replikę tylko do odczytu lub lokalna replika może utworzyć inną lokalną replikę o tej samej charakterystyce. Metoda GetObjectReplicability Metoda ta wskazuje na to, czy obiekt w bazie jest lokalny czy replikowany. Składnia prawidłowego wywołania GetObjectReplicability przedstawiona jest poniżej: Set ReturnValue = Replica.GetObjectReplicability(NazwaObiektu, _ TypObiektu) Metoda zwraca wartość logiczną wskazującą na to, czy obiekt może być replikowany. W bazach danych nieprzystosowanych do replikacji funkcja zwraca dla wszystkich obiektów True, ponieważ każdy z tych obiektów może zostać replikowany, mimo że nie został ustawiony żaden schemat replikacji. Jeżeli baza zostanie przekształcona do postaci replikowalnej, metoda zwróci True. W bazach replikowalnych metoda ta zwróci False dla wszystkich nowych obiektów, ponieważ domyślnie nie są one częścią schematu replikacji. Parametry metody GetObjectReplicability przedstawione są poniżej. NazwaObiektu – nazwa obiektu, z którego odczytywany jest stan replikacji. TypObiektu – typ obiektu wyszczególnionego w pierwszym parametrze. Metoda GetObjectReplicability wskazuje, czy obiekt jest lub może być replikowany. Parametry NazwaObiektu i TypObiektu są ciągami zawierającymi nazwę obiektu (np. Klienci) i nazwę części okna bazy danych (np. Tabele). Jeżeli obiekt o podanej nazwie i typie nie występuje w bazie, lub którykolwiek z ciągów będzie dłuższy niż 64 znaki, wystąpi błąd. Aby dowiedzieć się, w jaki sposób zmieniać stan replikacji obiektu, popatrz na opis metody SetObjectReplicability. Jeżeli obiekt określony parametrami NazwaObiektu i TypObiektu nie istnieje, wystąpi błąd. Metoda MakeReplicable Metoda ta przystosowuje bazę danych do replikacji. Składnia jej jest przedstawiona poniżej. Replica.MakeReplicable([CiągPołączenia] [,ŚledzenieKolumn]) CiągPołączenia – parametr opcjonalny. Ciąg zawierający nazwę i pełną ścieżkę dostępu do bazy danych. Wartość tego parametru zastępuje właściwość ActiveConnection. ŚledzenieKolumn – parametr opcjonalny. Wartość logiczna wskazująca na sposób śledzenia zmian, na poziomie kolumn lub na poziomie rekordów. Wartością domyślną jest True. Śledzenie zmian na poziomie kolumn pozwala na połączenie zmian w rekordzie, jeżeli dotyczyły różnych pól. Konflikt wystąpi, jeżeli różni użytkownicy zmienią to samo pole w rekordzie. Jeżeli w bazie często zdarzają się nakładające się zmiany tego samego rekordu, ustawienie tego parametru może spowodować polepszenie wydajności. Jeżeli nie poda się parametru CiągPołączenia oraz nie ma ustawionej właściwości ActiveConnection, wystąpi błąd. Po pomyślnym zakończeniu działania metody, zostaje ustawiona właściwość ActiveConnection. Metoda PopulatePartial Metoda ta służy do ładowania repliki częściowej. Replica.PopulatePartial(PełnaReplika) PełnaReplika – pełna ścieżka dostępu i nazwa bazy danych repliki, z którą będą wymieniane dane. Gdy synchronizujesz replikę częściową z pełną repliką, możliwe jest pozostawienie osieroconych rekordów w replice częściowej. Przykładowo, masz ustawiony filtr dla tabeli Klienci zawierający warunek Region ='NJ'. Jeżeli użytkownik zmieni w replice częściowej pole Region z NJ na OR i uruchomi metodę Synchronize, zmiana zostanie przeniesiona do pełnej repliki. Jednak rekord zawierający OR w polu Region pozostanie osierocony w replice częściowej, ponieważ nie spełnia warunków filtra. Aby uniknąć pozostawiania osieroconych rekordów w trakcie replikacji rekordów, należy użyć metody PopulatePartial. Metoda ta czyści wszystkie rekordy z repliki częściowej i ponownie ładuje je, bazując na ustawionym filtrze. Metoda PopulatePartial jest podobna do Synchronize, ale po synchronizacji wszystkich zmian z repliki częściowej do pełnej repliki usuwa wszystkie rekordy z repliki częściowej i ponownie ładuje replikę częściową, bazując na bieżącym filtrze repliki. Gwarantuje to, że zmiany poczynione w replice częściowej nie zostaną osierocone z powodu konfliktu filtra. Zawsze używaj metody PopulatePartial, gdy tworzysz replikę częściową lub zmieniasz warunek filtra repliki. Jeżeli aplikacja zmieniła warunek filtra, powinieneś wykonać następujące kroki: 115. Zsynchronizuj pełną replikę z replikami częściowymi, w których ma zostać zmieniony warunek filtra. 116. Użyj obiektu Filter, aby wprowadzić zmiany do warunku filtra repliki. 117. Wywołaj metodę PopulatePartial, aby usunąć wszystkie rekordy z repliki częściowej i przesłać wszystkie rekordy spełniające warunek filtra z pełnej repliki do repliki częściowej. Jeżeli zmieniony zostanie warunek filtra i zostanie wywołana metoda Synchronize bez wcześniejszego wywołania PopulatePartial, mogą wystąpić błędy. Metoda PopulatePartial może być wywołana tylko wtedy gdy replika częściowa zostanie otwarta na wyłączność. Co więcej, nie można wywołać PopulatePartial z programu działającego w replice częściowej. Zamiast tego, należy otworzyć na wyłączność replikę częściową z pełnej repliki lub innej bazy danych i wtedy wywołać metodę PopulatePartial. Mimo że PopulatePartial wykonuje jednokierunkową synchronizację przed wyczyszczeniem i powtórnym ładowaniem repliki częściowej, dobrym pomysłem jest wywołanie Synchronize przed PopulatePartial. Gdy używa się połączenia bezpośredniego lub połączenia internetowego, w razie wystąpienia błędu w trakcie metody Synchronize, wystąpi błąd, który można przechwycić. Można na podstawie tego błędu zdecydować, czy uruchamiać metodę PopulatePartial (która usuwa wszystkie rekordy z repliki częściowej). W wypadku synchronizacji pośredniej nie występuje przechwytywalny błąd, więcej informacji znajdziesz w opisie metody Synchronize. Jeżeli wywołana zostanie metoda PopulatePartial i wystąpi błąd w trakcie synchronizacji, rekordy w częściowej replice pozostaną usunięte. Nie jest to satysfakcjonujący rezultat. Metoda SetObjectReplicability Metoda ta decyduje, czy obiekt jest lokalny, czy replikowany. Ustawienie replikacji obiektu jest wykonywane przez wywołanie metody w następujący sposób: Replica.SetObjectReplicability(NazwaObiektu, TypObiektu, _ Replikowalność) NazwaObiektu – nazwa obiektu, w którym będzie ustawiany status replikacji. TypObiektu – typ obiektu, w którym będzie ustawiany status replikacji. Replikowalność – wartość logiczna wskazująca na to, czy obiekt może być replikowany. Metoda SetObjectReplicability powoduje, że obiekt jest replikowany lub pozostaje lokalny. Jeżeli baza danych nie została jeszcze przystosowana do replikacji, ustawienie parametru Replikowalność na False powoduje, że obiekt pozostanie lokalny po przystosowaniu bazy do replikacji. Obiekty w niereplikowalnych bazach danych są domyślnie replikowalne. Jednak nowe obiekty tworzone w replikowalnych bazach danych nie są domyślnie replikowalne. Aby zmienić nowy obiekt w replikowalnej bazie danych z lokalnego na replikowalny, należy ustawić parametr Replikowalność na True. Parametry NazwaObiektu i TypObiektu są ciągami zawierającymi nazwę obiektu (np. Klienci) i nazwę części okna bazy danych (np. Tabele). Jeżeli obiekt o podanej nazwie i typie nie występuje w bazie lub którykolwiek z ciągów będzie dłuższy niż 64 znaki, wystąpi błąd. Metoda SetObjectReplicability jest ignorowana dla wszystkich obiektów Accessa następujących typów: Formularze, Raporty, Strony, Makra i Moduły. Replikowalność tych obiektów jest kontrolowana poprzez tabelę MsysAccessObjects i może być ustawiona przed przystosowaniem bazy danych do replikacji. Domyślnie obiekty te są replikowalne. Informacje na temat sprawdzania replikowalności obiektów zawarte są przy opisie metody GetObjectReplicability. Metoda Synchronize Metoda ta powoduje synchronizację ze sobą dwóch replik zgodnie z ich właściwościami replikacji i parametrami wywołania metody. Replica.Synchronize(Cel [,TypSynchronizacji] (,TrybSynchronizacji]) Cel – ciąg zawierający nazwę i ścieżkę dostępu do repliki, z którą będzie się synchronizowała bieżąca replika, nazwę synchronizatora, który zarządza docelową repliką, lub serwer internetowy zawierający docelową replikę. TypSynchronizacji – parametr opcjonalny. Wartość wyliczeniowa określająca typ wykonywanej synchronizacji. Domyślną wartością jest jrSyncTypeImpExp. Prawidłowe wartości parametru wymienione zostały w tabeli 22.14. Tabela 22.14. Wartości parametru TypSynchronizacji Stała Wartość Opis jrSyncTypeExport 1 Wysyła zmiany z bieżącej repliki do docelowej jrSyncTypeImport 2 Wysyła zmiany z repliki docelowej do bieżącej jrSyncTypeImpExp 3 Wartość domyślna. Wysyła zmiany z bieżącej repliki do docelowej i odwrotnie TrybSynchronizacji – parametr opcjonalny. Wartość wyliczeniowa określająca tryb synchronizacji. Wartością domyślną jest jrSyncModeIndirect. Właściwe wartości parametru przedstawione są w tabeli 22.15. Tabela 22.15. Wartości parametru TrybSynchronizacji Stała Wartość Opis jrSyncModeIndirect 1 Wartość domyślna. Synchronizacja pośrednia jrSyncModeDirect 2 Synchronizacja bezpośrednia jrSyncModeInternet 3 Pośrednia synchronizacja przez Internet Replika podana jako wartość parametru Cel musi być częścią tego samego zbioru replik. Jeżeli obie repliki mają tę samą wartość właściwości ReplicaID, lub obie są wzorcami projektowania dwóch różnych zbiorów replik, replikacja się nie uda. Jest to wymuszone przez dostawcę. Jeżeli synchronizacja jest pośrednia, wartością parametru Cel musi być nazwą synchronizatora. Jet w czasie replikacji pozostawia zmiany w buforze. Synchronizator zarządzający docelową repliką pobiera te zmiany i nanosi je. Aby synchronizacja pośrednia działała prawidłowo, Synchronizator musi być uruchomiony na komputerze lokalnym i docelowym. Gdy synchronizacja ma zachodzić przez Internet, wartość parametru Cel musi być w postaci adresu URL zamiast ścieżki w sieci lokalnej. Jeżeli Cel jest w postaci adresu URL, a parametr TrybSynchronizacji nie jest jrSyncModeInternet, wystąpi błąd. Gdy tryb synchronizacji jest bezpośredni, obie repliki są jednocześnie otwierane i synchronizowane. Przy synchronizowaniu przez sieć WAN lub odległą sieć, pewność i wydajność procesu można poprawić używając synchronizacji pośredniej. Można również synchronizować dane z SQL Server i bazami danych Jet przez ustawienie parametru Cel na ServerName.Database.Publication i tryb synchronizacji na inny niż bezpośredni. Manager replikacji jest wymagany do zainstalowania i konfiguracji programów Synchronizer i Replman, za pomocą których można monitorować stan synchronizacji pośrednich i internetowych. Są one dostępne w wersji Developer Edition Office 2000. Więcej informacji na temat managera replikacji znajduje się w pomocy Accessa. Kolekcja Filters Kolekcja ta zawiera wszystkie obiekty Filter w replice. Każdy obiekt filtra pozwala na ograniczenie ilości replikowanych rekordów. Właściwości i metody kolekcji Filters wymienione są w tabeli 22.16. Tabela 22.16. Właściwości i metody kolecji Filters Właściwość Opis Właściwość Count Zwraca ilość filtrów w kolekcji Metoda Item Umożliwia dostęp do kolumn w kolekcji Metoda Append Dodaje nowy filtr do kolekcji Metoda Delete Usuwa filtr z kolekcji Metoda Refresh Uaktualnia obiekty w kolekcji, aby odzwierciedlić bieżące zmiany w projekcie bazy Właściwość Count Właściwość ta przechowuje ilość obiektów w kolekcji. Możesz użyć właściwości Count, aby sprawdzić, ile obiektów znajduje się w kolekcji. Ponieważ numerowanie elementów kolekcji zaczyna się od zera, powinieneś zawsze używać pętli rozpoczynających się od elementu zerowego i kończących się na wartości właściwości Count – 1. Jeżeli używasz Microsoft Visual Basic i chcesz utworzyć pętlę przebiegającą przez wszystkie elementy kolekcji, użyj konstrukcji For Each ... Next. Jeżeli wartość właściwości Count wynosi 0, kolekcja nie zawiera obiektów. Metoda Item Metoda ta zwraca obiekt z kolekcji identyfikowanej przez nazwę lub numer. Wywołanie metody pokazane jest poniżej: Set object = Collection.Item ( Indeks ) Zwraca odwołanie do obiektu. Indeks – wartość typu Variant, która może być nazwą lub numerem obiektu w kolekcji. Użyj metody Item, aby zwrócić określony obiekt w kolekcji. Jeżeli metoda nie może znaleźć obiektu odpowiadającego podanej wartości indeksu, wystąpi błąd. Niektóre kolekcje nie umożliwiają nazywania obiektów, dla nich musisz używać adresowania numerem. Właściwość Item jest właściwością domyślną dla wszystkich kolekcji, więc poniższe instrukcje są równoważne: Collection.Item( Indeks ) Collection( Indeks ) Metoda Append Metoda ta dodaje nowy obiekt Filter do kolekcji obiektów Filters w replice częściowej. Składnia metody Append jest następująca: Filters.Append(NazwaTabeli [, TypFiltra], KryteriaFiltra) NazwaTabeli – ciąg będący nazwą tabeli, na którą nakładany jest filtr. TypFiltra – wartość wyliczeniowa wskazująca na wartość właściwości FilterType określająca, czy filtr bazuje na tabeli, czy na relacji. KryteriaFiltra – ciąg zawierający kryteria, które spełniać musi rekord, aby był replikowany z pełnej repliki. Ustawia właściwość FilterCriteria. Jeżeli replika nie jest repliką częściową, wystąpi błąd. Jeżeli filtr o takiej samej nazwie i typie już istnieje, również wystąpi błąd. Wystąpi błąd, gdy spróbujesz dodać drugi filtr typu jrFltrTypeTable do tej samej tabeli. Metoda Delete Metoda ta usuwa obiekt Filter z kolekcji Filters w replice. Filters.Delete( Indeks ) Indeks – wartość typu Variant zawierająca nazwę lub numer obiektu Filter do skasowania. Jeżeli są dwa filtry o takiej samej nazwie, skasowany zostanie pierwszy. Użycie numeru pozwala na jednoznaczną identyfikację filtra w przypadku takich samych nazw filtrów. Jeżeli filtr o podanej nazwie lub numerze nie istnieje w kolekcji, wystąpi błąd. Metoda Refresh Metoda ta uaktualnia obiekty w kolekcji, aby odzwierciedlały dostępne obiekty. Wywołanie metody Refresh jest proste. Collection.Refresh Obiekt Filter Właściwość ta definiuje kryteria, jakie musi spełniać rekord, aby został replikowany z pełnej repliki. Właściwość FilterCriteria Umożliwia zapis i odczyt ciągu zawierającego kryteria. Dla filtrów opartych o tabelę ciąg powinien reprezentować klauzulę Where kwerendy SQL bez słowa Where. Dla filtrów opartych o relację ciąg zawiera nazwę relacji. Po ustawieniu wartości właściwość ta jest tylko do odczytu i może być zmieniana tylko przy użyciu metody Append. Wartością domyślną jest pusty ciąg znaków. Właściwość FilterType Właściwość ta określa typ filtra. Właściwość jest typu wyliczeniowego. Prawidłowymi wartościami są stałe zamieszczone w tabeli 22.17. Właściwość ta jest tylko do odczytu i można ją zmieniać tylko za pomocą metody Append. Tabela 22.17. Wartości FilterType Stała Opis jrFltrTypeTable Wartość domyślna. Filtr jest oparty o tabelę jrFltrTypeRelationship Filtr jest oparty o relację Właściwość TableName Właściwość ta przechowuje nazwę tabeli, na którą nakładany jest filtr. Właściwość przechowuje ciąg określający nazwę tabeli. Dla filtrów opartych o relacje, jest to tabela będąca po stronie relacji wiele. TableName jest tylko do odczytu i może być zmieniane przy użyciu metody Append. Rozdział 23. Bezpieczeństwo W tym rozdziale: ? Elementy bezpieczeństwa. ? Tworzenie grupy roboczej. ? Użytkownicy i grupy. ? Tworzenie systemu bezpieczeństwa przy użyciu opcji startowych. ? Zagadnienia bezpieczeństwa przy użyciu replikacji. ? Ochrona dzielonych baz danych. ? Bezpieczeństwo systemu klient-serwer. ? Zabezpieczanie bazy danych krok po kroku. ? Częste błędy bezpieczeństwa. Aplikacje, a w szczególności aplikacje wieloużytkownikowe, nie są dokończone, dopóki nie zostaną zabezpieczone. Bez prawidłowo wykonanego systemu ochrony aplikacje są podatne na ataki złośliwych hackerów i niewinną ciekawość niedoświadczonych użytkowników. Jednak pomimo olbrzymich możliwości systemu bezpieczeństwa Jet jest on zwykle w bazach Accessa zaniedbywany lub niewłaściwie tworzony. Częściowo dlatego, że opracowanie właściwej struktury bezpieczeństwa jest niełatwym zadaniem. Opisy sposobów tworzenia systemu bezpieczeństwa są mylące, a sposób, w jaki Jet obsługuje system bezpieczeństwa, różni się od innych systemów baz danych. Elementy bezpieczeństwa W tym rozdziale skupimy się na modelu bezpieczeństwa opartym o grupę roboczą stosowanym w Jet. Wskażemy wiele praktycznych zagadnieniach, które musisz rozważyć w trakcie zabezpieczania bazy danych. Pokażemy również techniki ActiveX Data Object Extensions for Database Definition Language and Security (ADOX) do tworzenia funkcji zabezpieczeń. ADOX korzysta z interfejsu programistycznego DAO dla definicji danych i zarządzania ochroną. ADOX zapewnia prostszy model obiektowy, a gdy używamy dostawcy OLEDB, model nie zawiera różnic syntaktycznych. Ponieważ ADOX obsługuje tylko źródła danych oraz obiekty oparte na danych, takich jak tabele, kwerendy, widoki i procedury, omówione zostaną podstawy interfejsu i techniki DAO. Pozwoli to zastosować system bezpieczeństwa dla formularzy, raportów i makr. Istnieją dwie możliwości zabezpieczenia aplikacji Accessa 2000: ? Ustawienie hasła bazy danych. ? Utworzenie systemu bezpieczeństwa opartego o grupę roboczą. Zabezpieczenie bazy danych hasłem Ustawienie hasła bazy danych jest szybką i prostą metodą zabezpieczenia pliku MDB. Po jej zastosowaniu (menu Narzędzia, Zabezpieczenia, Ustaw hasło bazy danych w bazie otwartej na wyłączność) wszystkim użytkownikom zostanie przypisane to samo hasło. W czasie uruchamiania pliku MDB każdy użytkownik musi podać to hasło. Wszyscy mają to samo hasło i przez to każdy, kto zna hasło, może dostać się do bazy. Łatwo zauważyć, że ten sposób jest dużym kompromisem, gdy wszyscy użytkownicy mają te same prawa i hasło. Użytkownicy są nieodróżnialni od siebie. Dodatkowo, jeżeli hasło zostanie zapomniane, nie ma sposobu na jego odtworzenie. I na koniec, założenie hasła na bazę danych wyklucza użycie replikacji. Samo hasło bazy danych nie jest najlepszą metodą na zabezpieczenie poważnej aplikacji wieloużytkownikowej, jednak może być używane razem z grupą roboczą. System bezpieczeństwa grupy roboczej jest bardziej skomplikowany od hasła bazy. W tym rozdziale skupimy się na tym zagadnieniu. System bezpieczeństwa grupy roboczej Hasło bazy oparte jest o bazę danych (chroniona jest baza danych bez rozróżniania użytkowników), natomiast Access/Jet jest zabezpieczany w oparciu o informacje podawane przy logowaniu do grupy roboczej. Jest to skomplikowany i elastyczny system, gdzie identyfikacja użytkownika w grupie roboczej determinuje sposób pracy schematu bezpieczeństwa. W tej strukturze bezpieczeństwa użytkownicy są jednoznacznie identyfikowani i mogą indywidualnie dostawać uprawnienia do bazy i zawartych w niej obiektów. Można powiedzieć, że dyskusja o plikach grupy roboczej, przestrzeniach roboczych i grupach, która zostanie zaraz przeprowadzona, jest w rzeczywistości dyskusją o organizacji, rozszerzaniu i ułatwianiu podstawowych operacji tworzenia i przypisywania praw użytkownikom. Taki system oparty o użytkowników nie jest administrowany przez Access ani Jet. Jest administrowany za pomocą pliku grupy roboczej (system.mdw). Plik grupy roboczej zawiera informacje na temat uprawnień użytkowników i grup użytkowników i jest używany przez Accessa do odczytywania tych uprawnień. W Accessie system zabezpieczeń jest zawsze włączony, jednak nie jest on zwykle widoczny. Plik grupy roboczej jest zawsze używany, niezależnie od tego czy efekty są widoczne. Z tego powodu bardzo ważne jest ustawienie odpowiedniej grupy roboczej przed rozpoczęciem prac nad systemem bezpieczeństwa. Stosowanie takiego modelu (z oddzielną administracją) powoduje, że grupy użytkowników mogą mieć różne aplikacje zabezpieczane i administrowane przez jeden centralny plik bezpieczeństwa. Plik MDW używany przez bazę danych definiuje grupę roboczą. Grupa robocza jest zbiorem użytkowników, ich grup i baz danych, których mogą używać. Jak pokazane jest na rysunku 23.1, silnik bazy danych polega na jego przestrzeni roboczej, aby dostarczyć informacji na temat użytkowników bazy danych. Rysunek 23.1. Zauważ, że w tym schemacie nie ma obiektów bazy danych. Mimo że użytkownik jest centrum systemu bezpieczeństwa, nie jest możliwe tworzenie użytkownika lub przeprowadzenie znaczącej dyskusji o nim, bez umieszczania go w kontekście grupy. Grupa robocza musi istnieć, aby działał system bezpieczeństwa. Możesz mieć wielu użytkowników lub tylko jednego, ale grupa musi być utworzona. Plik grupy roboczej jest specjalną szyfrowaną bazą danych, która zawiera następujące informacje: ? nazwa użytkownika; ? hasło użytkownika; ? identyfikator użytkownika (PID); ? właściwości użytkownika (ustawienia paska narzędzi i niektóre wartości domyślne); ? ostatnie cztery bazy otwarte przez użytkownika (widoczne w menu Plik); ? nazwy grup; ? grupy (PID); ? członków grup (użytkownicy należący do grupy). Tworzenie grupy roboczej Zaraz po zainstalowaniu, Access jest podłączony do domyślnej grupy roboczej definiowanej przez plik system.mdw. System.mdw jest utworzony jedynie dla wygody. Gdy jest on tworzony w trakcie instalacji, informacje krytyczne dla działania systemu bezpieczeństwa są pozostawione poza nim, więc są one na stałe niechronione. Każdy, kto chce zobaczyć plik pomocy Accessa, musi przebić się przez ochronę domyślnego system.mdw. Powinieneś pozostawić ten plik i w razie potrzeby utworzyć nowy plik grupy roboczej. Aby to wykonać, należy użyć programu wrkgadm.exe, który zwykle jest instalowany w ...\Microsoft Office\Office\wrkgadm.exe. Program ten pozwala na tworzenie nowych grup roboczych i przyłączanie się do już istniejących. Po utworzeniu grupy wynikowy plik MDW powinien być umieszczony w sieci w katalogu dostępnym dla wszystkich spodziewanych użytkowników. W czasie tworzenia pliku grupy roboczej nie musisz mieć szczegółowego planu struktury systemu bezpieczeństwa, jednak dobrze jest utworzyć plik grupy roboczej w trakcie tworzenia aplikacji najszybciej jak to tylko możliwe, aby uniknąć w przyszłości pomyłek. W czasie pracy wrkgadm.exe musisz wybrać pomiędzy podłączeniem do istniejącej grupy lub tworzeniem nowej. Po wybraniu tworzenia nowego pliku grupy roboczej musisz podać informacje na temat przynależności do grupy roboczej. Jak widać na rysunku 23.2 w oknie są trzy pola. Administrator grupy roboczej wypełnia dwa z tych pól, odczytując je z instalacji Office 2000 lub Accessa 2000. Możesz zmienić te dwa pola albo zostawić je bez zmian, jednak musisz wprowadzić identyfikator grupy. Rysunek 23.2. Przed utworzeniem grupy roboczej zapisz te krytyczne informacje Rysunek 23.3. Access automatyzuje wprowadzanie niektórych informacji w Administratorze grupy, jednak nadal możesz je zmienić Identyfikator grupy dostarcza ziarna dla algorytmu szyfrowania pliku grupy roboczej. Jest to informacja, która nie jest tworzona w trakcie instalacji. Administrator pozwala na pozostawienie tego pola pustego, ostrzegając wcześniej o tym fakcie, jednak neguje to cel tworzenia grupy roboczej. Identyfikator grupy zawiera do 20 znaków i wielkość znaków jest istotna. Ciąg, który wprowadziłeś zapewnia, że grupa robocza będzie unikatowa po utworzeniu binarnego identyfikatora nazywanego Workgroup Security ID (SID). Jeżeli właściwie zabezpieczysz identyfikator grupy, nie może ona zostać przejęta. System bezpieczeństwa tak silnie chroni ten ciąg, że masz jeszcze tylko jedną szansę na zobaczenie lub zmianę jego wartości. Zapisz ten ciąg i przechowuj tak, aby osoby niepowołane nie miały do niego dostępu. Zapisz wartość identyfikatora grupy i przechowuj w bezpiecznym miejscu. Możesz jej potrzebować, aby powtórnie utworzyć grupę roboczą. Jet nigdy nie udostępni tej wartości. Następnym krokiem jest znalezienie odpowiedniego miejsca dla pliku grupy roboczej. Powinien być umieszczony w katalogu, w którym wszyscy użytkownicy grupy mają prawo do zapisu i odczytu. Jednak, gdy użytkownicy nie zmieniają się, można skopiować plik MDW do komputerów wszystkich użytkowników. Jeżeli plik zmieni się, operację należy powtórzyć, co może spowodować, że większe nakłady na administrację przeważą zysk wydajności. Umieszczenie pliku MDW na dysku sieciowym zwiększa szanse, że będzie on regularnie składowany, co ułatwia odzyskiwanie danych w wypadku awarii. Nie ulegaj pokusie nazwania pliku MDB tak samo jak aplikacji lub źródła danych, jeżeli pliki te umieszczone są w tym samym katalogu. Plik MDW tworzy plik LDB do przechowywania informacji o swoich blokadach, tak samo jak źródło danych i aplikacja. Jeżeli pliki MDB i MDW mają tę samą nazwę, to mimo że nie są ze sobą w konflikcie, to ich pliki LDB nie zgodzą się ze sobą. Dobrym rozwiązaniem jest poprzedzenie nazwy pliku ciągiem „SYS” lub „SYS_”. Ostatnią szansą na zmianę lub obejrzenie informacji o grupie jest okno potwierdzenia danych o grupie roboczej. Upewnij się, że prawidłowo zapisałeś wszystkie te informacje, a w szczególności identyfikator grupy, ponieważ może być on potrzebny, aby odtworzyć plik MDW. Jeżeli potwierdzisz informacje o grupie, administrator potwierdzi fakt utworzenia grupy roboczej i powróci do pierwszego okna dialogowego. Zauważ, że podłączyłeś się do nowej grupy roboczej. Możesz teraz tworzyć bazy danych, użytkowników i grupy, przypisywać użytkowników do grup oraz nadawać i odbierać prawa w tej grupie roboczej. Jeżeli podłączysz się do innej grupy roboczej, możesz w niej pracować w obszarze przydzielonych uprawnień. Aby nie zniszczyć żadnej istniejącej bazy danych, utwórz całkiem nową bazę danych, na której przetestujemy resztę cech systemu bezpieczeństwa. Jeżeli Access jest otwarty, zamknij go i uruchom ponownie. Spowoduje to uruchomienie Accessa w nowo utworzonej grupie roboczej, chociaż nic na to nie wskazuje. Przed utworzeniem uprawnień jest bardzo ważne sprawdzenie, czy dołączyłeś się do właściwej grupy roboczej. Możesz ustawić przynależność bazy danych do grupy roboczej przez wpisanie odpowiednich parametrów wywołania bazy danych: Ścieżka do Access.exe Ścieżka do MDB /WRKGRP Ścieżka do pliku MDW [/USER nazwa użytkownika /PWD hasło] Parametry wywołania /WRKGRP, /USER, /PWD działają tylko dla baz danych Accessa, nie dla projektów Accessa. Użytkownicy i grupy Użytkownicy są podstawą systemu bezpieczeństwa. Jet rozpoznaje użytkowników i wie, co każdy z nich może zrobić. Co każdy z użytkowników może zrobić zależy od uprawnień nadanych bezpośrednio użytkownikowi lub które odziedziczył z grup, do których należy. Uprawnienia użytkowników są sumą ich uprawnień pochodzących z grup (uprawnienia wynikowe) oraz ich indywidualnych uprawnień (uprawnienia bezpośrednie). Użytkownik należy do co najmniej jednej grupy, grupy Użytkownicy. W trakcie logowania się do bazy danych Jet zawsze logujesz się jako użytkownik. Nie można zalogować się jako grupa. System zabezpieczeń rozpoznaje, do jakich grup należysz i stosuje się do posiadanych przez Ciebie uprawnień. Chociaż użytkownicy są podstawowym elementem systemu bezpieczeństwa, trudno jest dyskutować o nich bez brania pod uwagę grup, ponieważ użytkownik zawsze należy do co najmniej jednej grupy, a grupy są stworzone do zarządzania użytkownikami. Rozważmy przypadek hipotetycznej grupy Urzędnik. Mimo że grupa może nie posiadać uprawnień do tworzenia i modyfikacji obiektów, może być w niej jeden użytkownik, który jest wyznaczony do korygowania i tworzenia raportów. Powinien on otrzymać bezpośrednie prawo do tworzenia i modyfikacji obiektów raportów, mimo że nikt w grupie Urzędnik takiego prawa nie posiada. Mimo że to działa, powoduje kłopoty w administracji, ponieważ administrator zabezpieczeń musi zajmować się indywidualnymi użytkownikami oraz grupami. Istnieje szansa, że jeżeli administrator zrobił jeden wyjątek, zrobi i kolejny. Lepszym sposobem obsługi urzędnika tworzącego raporty jest przypisanie go do grupy, która posiada uprawnienia do tworzenia i modyfikacji raportów. Tym sposobem administrator obsługuje funkcjonalne możliwości pojedynczych użytkowników zamiast opracowywać ich indywidualne profile zabezpieczeń. Grupy nie mogą należeć do grup. Ponieważ raporty są tworzone przez kreatorów, a budowniczy zapytań pomaga użytkownikom precyzyjnie definiować wymagane dane bez dodawania obiektów zapytań do bazy danych, możliwe jest danie szerokich uprawnień do tworzenia raportów, nawet w zabezpieczonej bazie danych. Zaoszczędzi to mnóstwo nudnej pracy przy ich tworzeniu. Grupa Użytkownicy domyślnie posiada wszystkie uprawnienia, a każdy użytkownik jest jej członkiem. Musisz usunąć wszystkie uprawnienia z grupy Użytkownicy, aby prawidłowo zabezpieczyć bazę danych. Inaczej każdy użytkownik bazy będzie dziedziczył prawa administratora. Omówienie domyślnych ustawień użytkowników i grup Przed rozpoczęciem pracy nad zabezpieczeniami należy zapoznać z domyślnymi ustawieniami. Jet rozpoczyna pracę z dwiema grupami i jednym domyślnym użytkownikiem. Te dwie grupy to Administratorzy i Użytkownicy. Domyślnym użytkownikiem jest Administrator. Administrator jest członkiem obu grup, a obie grupy posiadają wszystkie uprawnienia w bazie danych. Gdy tworzymy kolejnych użytkowników i grupy, nazwy grup i nazwy użytkowników nie mogą być takie same. Access używa konwencji nazywania użytkowników w liczbie pojedynczej, a grup w liczbie mnogiej. Wydaje się być to dobrym rozwiązaniem i należy stosować tę konwencję. Najważniejszą grupą jest grupa Administratorzy, ponieważ ma ona specjalne uprawnienia, które nie mogą być nadawane tworzonym przez Ciebie grupom. Aby tworzyć, zmieniać lub usuwać użytkowników, tworzyć lub usuwać grupy, zmieniać przynależność do grupy lub wyczyścić hasło użytkownika, musisz być członkiem grupy Administratorzy. Użytkownik nie będący członkiem tej grupy może oglądać dane o innych użytkownikach i sprawdzić, kto należy do grupy, ale nie może zmienić żadnego z tych ustawień, nawet dla siebie. Może on tylko zmieniać swoje hasło. Oczywiście w bazie danych musi być co najmniej jeden użytkownik należący do grupy Administratorzy. Grupy nie są tylko zbiorem użytkowników. Mimo że nie mogą się logować do bazy i nie mogą posiadać własnego hasła ani być właścicielem bazy danych, mogą jednak być właścicielami obiektów Accessa i posiadać różne uprawnienia. Ta możliwość pozwala na ułatwienie administracji bazą danych i użytkownikami. Jako generalną zasadę powinieneś przyjąć, że przypisujesz uprawnienia grupom, a następnie przypisujesz użytkowników do grup. Bardzo ułatwia to administrowanie systemem zabezpieczeń. Tworzenie użytkowników Mimo że użytkownik może różnić się tylko szczegółami od innych użytkowników tej samej grupy, tworzenie użytkowników jest niezbędne do prawidłowego funkcjonowania systemu bezpieczeństwa w bazie danych. Aby utworzyć użytkownika, należy wykonać następujące kroki: 118. Z menu Narzędzia wybrać Zabezpieczenia, Konta użytkowników i grup. 119. Wybrać zakładkę Użytkownicy i kliknąć przycisk Nowa. 120. Wprowadź Nazwę i Identyfikator osobisty (PID), w sposób pokazany na rysunku 23.4. PID musi mieć od 4 do 20 znaków. Wielkość liter ma znaczenie. Służy on jako ziarno dla tworzenia identyfikatora zabezpieczeń (SID). Musisz zapisać PID, ponieważ nie da się go później odczytać. Rysunek 23.4. Tworzenie nowego użytkownika i przypisywanie mu identyfikatora PID Ustawianie i zmiana hasła użytkownika Po utworzeniu użytkownika możesz przypisać mu hasło. Nie musisz tego robić, ale powinna być to standardowa procedura. Kliknij zakładkę Zmienianie hasła logowania, aby zmienić lub ustawić hasło. Hasło powinno posiadać od 1 do 14 znaków i nie jest obowiązkowe. Wielkość liter w haśle ma znaczenie. Ponieważ hasło jest przeznaczone do tego, aby sprawdzić, że użytkownik jest tym, za kogo się przedstawia, każdy powinien mieć założone hasło. Nie można podejrzeć hasła po jego ustawieniu, więc lepiej je zapisać. W najgorszym przypadku, jeżeli użytkownik zapomniał hasła, administrator może je usunąć. Na rysunku 23.5 widać, w jaki sposób ukrywane jest hasło podczas jego zmiany. Rysunek 23.5. Zmiana hasła użytkownika poprzez okno Accessa Zawodowa odpowiedzialność nie pozwala mi na podanie sposobów złamania zabezpieczeń Accessa pozwalających na odtworzenie zapomnianego hasła. Pamiętaj, aby używać hasła, którego nie zapomnisz, a nikt inny nie będzie go znał. Gdy wybierzesz takie hasło dobrze je zapamiętaj lub zapisz i przechowuj w bezpiecznym miejscu. Tworzenie grup Jak wspomnieliśmy wcześniej, grupy pozwalają na ułatwienie administracji przez ustawianie identycznego profilu zabezpieczeń wszystkim członkom grupy. Aby utworzyć grupę, wykonaj następujące czynności: 121. Z menu Narzędzia wybierz Zabezpieczenia, Konta użytkowników i grup. 122. Wybierz zakładkę Grupy i kliknij przycisk Nowa. 123. Wprowadź Nazwę i Identyfikator osobisty (PID). PID musi mieć od 4 do 20 znaków. Wielkość liter ma znaczenie. Służy on jako ziarno dla tworzenia identyfikatora zabezpieczeń (SID). Musisz zapisać PID, ponieważ nie da się go później odczytać (rysunek 23.6). Rysunek 23.6. Tworzenie grupy przez nadanie jej nazwy i PID przez interfejs użytkownika PID grupy jest ziarnem używanym do jednoznacznej identyfikacji grupy. Jeżeli kiedykolwiek będziesz potrzebował odtworzyć grupę, musisz podać ten sam PID. Zapisz go i przechowuj w bezpiecznym miejscu. Przypisywanie użytkowników do grup Użytkownicy i grupy są tak ściśle związani, że ich tworzenie i przypisywanie jest wykonywane w jednym miejscu. Użyj tej samej zakładki okna Konta użytkowników i grup, gdzie tworzyłeś użytkownika, aby połączyć go z grupą. Wykonaj następujące kroki: 124. U góry okna wybierz użytkownika. 125. Na dole okna dialogowego wybierz z listy Dostępne grupy grupę, do której chcesz przypisać użytkownika. 126. Dwukrotnie kliknij wybraną grupę lub użyj przycisku Dodaj, aby dodać użytkownika do grupy. Możesz również usunąć użytkownika z grupy przez dwukrotne kliknięcie w liście Członek grupy lub używając przycisku Usuń. Nie można usunąć użytkownika z grupy Użytkownicy. Aby zobaczyć wszystkie przypisania w bazie, użyj przycisku Drukuj użytkowników i grupy. Ponieważ system bezpieczeństwa jest zorientowany na użytkownika, można kontrolować skład grupy tylko z zakładki Użytkownicy, a nie zakładki Grupy. Rozróżnianie między domyślnymi i specjalnymi grupami i użytkownikami Po utworzeniu nowej bazy danych struktura bezpieczeństwa Accessa nie jest pozbawiona użytkowników i grup. Posiada ona zestaw domyślnych użytkowników i grup. Ci użytkownicy i grupy muszą istnieć, aby system bezpieczeństwa działał poprawnie. Dopóki Access nie wie, kto się loguje do bazy, wszyscy są identyfikowani jako użytkownik Administrator, który jest członkiem domyślnych grup Użytkownicy i Administratorzy, do czasu utworzenia systemu bezpieczeństwa. Grupy te nie powinny posiadać żadnego znaczenia w Twoim systemie bezpieczeństwa. W tej części opisane są te domyślne grupy. Administratorzy – w odróżnieniu od zwykłych kont, grupa Administratorzy jest unikatowa w każdej grupie roboczej, ponieważ jej SID jest generowany na podstawie SID grupy. Grupa Administratorzy musi zawsze posiadać co najmniej jednego członka i Jet wymusza tę regułę. Mimo że członkostwo w grupie Administratorzy może być odebrane, grupa nadaje specjalne niemożliwe do odebrania przywileje. Członek grupy Administratorzy może nadawać przywileje do każdego obiektu w grupie roboczej. Przy użyciu DAO i ADOX możliwe jest zablokowanie tych przywilejów dla Administratorów do obiektów bazy danych tak, aby specjalne przywileje posiadał tylko właściciel obiektów, jednak nie da się, ani używając DAO ani ADOX, odebrać Administratorom prawa do administracji grupami i kontami użytkowników. Administrator – jedyny domyślny użytkownik w Jet. Sam nie posiada żadnych specjalnych praw, jednak dziedziczy prawa z grupy Administratorzy. Jeżeli nie zalogowałeś się do bazy za pomocą konta jakiegoś użytkownika, domyślnie jesteś zalogowany jako Administrator. Jeżeli w grupie Administratorzy znajduje się jakiś inny użytkownik, możesz usunąć z niej użytkownika Administrator. Jest to niezbędny krok do prawidłowego zabezpieczenia bazy danych i jest omówiony w tym rozdziale w części „Zabezpieczanie bazy danych krok po kroku”. Użytkownicy – po utworzeniu bazy grupa ta jest pusta i domyślnie posiada wszystkie prawa do bazy. Usunięcie wszystkich praw z tej grupy jest niezbędnym krokiem do prawidłowego zabezpieczenia bazy danych i jest on omówiony w tym rozdziale w części „Zabezpieczanie bazy danych krok po kroku”. Właściciel – jest nim użytkownik, który utworzył obiekt, lub użytkownik, na którego zostało przeniesione posiadanie obiektu. Właściciel obiektu jest najsilniejszym użytkownikiem i posiada do niego nieusuwalne prawa. Właścicielami obiektów bazy danych muszą być użytkownicy, natomiast innych obiektów użytkownicy lub grupy. Poznajemy uprawnienia Tak jak trudno jest pisać o użytkownikach bez wspominania o grupach, równie trudno jest opisać uprawnienia bez napisania o obiektach. Po utworzeniu użytkowników i grup można rozpocząć tworzenie własnego systemu bezpieczeństwa. Uprawnienia określają, co użytkownik lub grupa może, a czego nie może zrobić z tabelami bazy danych, kwerendami, formularzami, raportami i makrami (moduły nie wchodzą już w skład systemu bezpieczeństwa). Typy uprawnień różnią się między obiektami, a niektóre uprawnienia zależą od innych uprawnień. Przykładowo, jeżeli masz prawo do zmiany wyglądu obiektu, musisz mieć możliwość otwarcia go (być może na wyłączność), odczytania i zapisu. Nie ma potrzeby zapamiętywania niezależnych i zależnych zbiorów uprawnień. Interfejs Accessa będzie się troszczył o to za Ciebie, musisz tylko wiedzieć, o co w tym chodzi. W tabeli 23.1 zestawione są obiekty, ich uprawnienia i ich konsekwencje. Uprawnienia nie są pamiętane w pliku MDW (w pliku MDW nie ma żadnej o nich informacji). Przechowywane są w bazie danych, a tylko użytkownicy są autoryzowani za pomocą pliku MDW. Tabela 23.1. Uprawnienia i co one mogą dla Ciebie zrobić Uprawnienie Opis Obiekt Otwórz z wyłącznością Otwieranie z zabronieniem innym dostępu do obiektu Baza danych Otwórz/Uruchom Otwieranie w trybie pracy Baza danych Czytanie projektu Otwieranie w trybie projektowania Wszystkie poza modułami Modyfikuj projekt Oglądanie, zmiana lub usuwanie obiektów struktury i ich właściwości Wszystkie Administruj (baza danych) Ustawianie hasła bazy danych, tworzenie wzorca replikacji, zmiana opcji startowych. Bez administracji uprawnieniami Baza danych Administruj (inne) Pełne prawa, włączając administrowanie uprawnieniami Wszystkie poza bazą danych Odczytaj dane Tylko odczyt danych Tabele i zapytania Aktualizuj dane Oglądanie i zmiana danych, bez dopisywania i kasowania Tabele i zapytania Wstaw dane Oglądanie i dopisywanie danych, bez zmieniania i usuwania Tabele i zapytania Usuń dane Oglądanie i usuwanie danych, bez zmieniania i wstawiania Tabele i zapytania Aby naprawić lub zmniejszać bazę danych, należy otworzyć ją na wyłączność. Tak samo należy otworzyć udostępnioną użytkownikom wielodostępną bazę danych, jeżeli trzeba wprowadzić do niej zmiany. Często pojawiają się problemy związane z zapytaniami. Można utworzyć dla użytkowników kwerendę, lecz nie chcesz, aby mieli oni dostęp do tabel, na których ona bazuje. Włączenie opcji Uruchom uprawnienia właściciela daje dostęp na poziomie rekordów i pól, ponieważ możesz ograniczyć użytkowników tylko do rekordów spełniających określone warunki (na przykład: kody oddziałów, numery pracowników, bieżące daty, wartości pól itd.) oraz nie mogą oni zmieniać utworzonych przez Ciebie zapytań. Właściwości Uruchom uprawnienia znajduje się w oknie opcji dostępnym przez Narzędzia? Opcje na zakładce Tabele/Kwerendy. Wybranie Właściciela (rysunek 23.7) udostępnia wszystkie uprawnienia posiadane przez właściciela kwerendy, na czas uruchomienia lub otwarcia kwerendy, jednak tylko właściciel może zmieniać zapytanie i tylko właściciel może oddać posiadaną kwerendę innemu użytkownikowi. Wybranie Właściciela przesłania bieżące uprawnienia użytkownika. Opcja ta może zostać uruchomiona z okna właściwości kwerendy oraz przez użycie klauzuli With OwnerAccess w wyrażeniu SQL (więcej na ten temat w „Konsekwencje w czasie używania SQL”). Rysunek 23.7. Ustawienie właściwości Uruchom uprawnienia dla kwerendy poprzez interfejs użytkownika Przez wszystkie lata tworzenia aplikacji baz danych nie spotkałem się z wieloma, o których można powiedzieć, że są skończone. Jeżeli baza danych jest używana i użytkownicy ją lubią, jest zwykle rozszerzana. Aby obsłużyć ewentualne nowe obiekty utworzone w przyszłości, Access dostarcza mechanizmu obsługi uprawnień obiektów, które jeszcze nie zostały utworzone w trakcie tworzenia systemu bezpieczeństwa. Wybranie w oknie dialogowym Uprawnienia użytkowników i grup nie zabezpiecza przed tworzeniem nowych obiektów tylko definiuje, jakie będą uprawnienia nowo utworzonego obiektu. Nawet, gdy usunie się wszystkie uprawnienia dla , użytkownicy będą mogli utworzyć nowe obiekty. Ponieważ użytkownik tworzący obiekt jest jego właścicielem, może ustawić dowolne uprawnienia do obiektu. Jedyną metodą zabronienia użytkownikom tworzenia obiektów jest interwencja w przypisywanie uprawnień przez ADO lub ADOX. Właściciel obiektu jest najsilniejszym użytkownikiem obiektu i może zrobić z nim wszystko. Nie można praw związanych z właściwością odebrać ani usunąć. Okno uprawnień może sugerować, że uprawnienia dla właściciela zostały odebrane, ale w rzeczywistości tak nie jest. Jedynym sposobem na pozbawienie praw jest przeniesienie właściwości na innego użytkownika. Użytkownik, który utworzył bazę danych, jest jej właścicielem. Jego prawa do tworzenia obiektów w bazie danych nie można odebrać, niezależnie co wskazuje okno nadawania uprawnień. Inni użytkownicy mogą tworzyć obiekty w bazie danych i stają się ich właścicielami. Aby ułatwić administrację, należy prawo właściwości przenieść na grupę, tym sposobem każdy członek grupy może administrować obiektem lub zbiorem obiektów. Prawo właściwości obiektu może zostać przeniesione przez właściciela bazy danych lub właściciela obiektu. Aby zmienić właściciela bazy danych, użytkownik musi posiadać prawa Czytanie projektu i Odczytaj dane w oryginalnej bazie danych. Następnie należy utworzyć bazę danych w grupie roboczej, zaimportować wszystkie obiekty do nowej bazy, usunąć oryginalną bazę oraz zmienić nazwę nowej bazy na taką jak usunięty oryginał. Tworzenie systemu bezpieczeństwa przy użyciu opcji startowych Oprócz rygorystycznego, prawidłowo zaprojektowanego systemu zabezpieczeń, powinieneś ustawić kilka opcji startowych, aby poprawić bezpieczeństwo Accessa. Nie powinno być to mylone lub używane zamiast właściwego systemu bezpieczeństwa, może jednak załatać jakąś nieprzewidzianą dziurę. To rozwiązanie może służyć jako tymczasowe zabezpieczenie aplikacji. W menu Autostart znajduje się kilka opcji: 127. Wyświetl okno bazy danych. W oknie bazy danych użytkownicy mogą zrobić najwięcej szkody. Poprzez ukrycie tego okna po wczytaniu bazy danych, mniej doświadczeni (i zwykle najbardziej ciekawi) użytkownicy nie będą mieli ochoty na zabawę tym oknem. 128. Pasek menu skrótów. Danie użytkownikowi dostępu do podstawowych możliwości Accessa może spowodować, że mała wyrwa w systemie bezpieczeństwa powiększy się. Nie pozwalaj zamknąć formatki innym sposobem niż ten, który przewidziałeś, lub zapisać dane bez sprawdzenia tożsamości i uprawnień bieżącego użytkownika. Wyłączenie pełnego menu, domyślnych skrótów klawiszowych, pasków narzędzi oraz dostosowywania menu i pasków narzędzi może zabezpieczyć przed włamaniem. Dokładnie przemyśl, które z opcji pozostaną aktywne. 129. Wyświetl kod po błędzie. Bez właściwego systemu bezpieczeństwa (i odpowiedniej obsługi błędów) użytkownicy mogą otrzymać na ekran denerwujący i tajemniczy komunikat błędu lub, co gorsza, kod programu, co jest skrajnie niewłaściwym i kłopotliwym zachowaniem aplikacji. Należy wyłączyć tę opcję. 130. Użyj specjalnych klawiszy programu Access. Naciśnięcie F11, Control-Break, Control-G może zrujnować aplikację. Wyłącz tą opcję przed wysłaniem aplikacji do klientów. 131. Ikona aplikacji. Tutaj można wskazać inną ikonę, która zastąpi ikonę Accessa. Jeżeli tego nie zrobisz, niektórzy użytkownicy mogą mieć kłopoty z odróżnieniem czy pracują w Accessie, czy w Twojej aplikacji. Można tutaj podać nazwę pliku z ikoną (ICO) lub rysunkiem (BMP). Zagadnienia bezpieczeństwa przy użyciu replikacji Użycie replikacji w aplikacji powoduje wystąpienie problemów, które daje się jednak rozwiązać. Repliki mogą być zabezpieczane na poziomie użytkowników. Wszystkie zmiany wprowadzane do uprawnień obiektów wzorca projektowania zostaną w trakcie synchronizacji rozprowadzone do wszystkich replik, ponieważ uprawnienia te stanowią część samych obiektów. Niestety plik grupy roboczej nie jest replikowany. Jeżeli użytkownicy nie mogą używać wspólnego pliku grupy roboczej, co zdarza się w większości struktur replikacji, plik grupy roboczej musi być rozprowadzany, gdy utworzony zostanie nowy obiekt lub gdy inne zmiany w strukturze zabezpieczeń tego wymagają. Innym problemem do rozpatrzenia jest skład grupy Administratorzy. Ponieważ członkowie tej grupy mogą dodawać i usuwać użytkowników oraz usuwać hasła, ważne jest, aby ostrożnie dobierać administratorów i utrzymywać najmniejszą możliwą ich liczbę. Gdy używana jest replikacja, niedostępne jest zabezpieczenie bazy danych hasłem. Ochrona podzielonych baz danych Bazy danych Accessa zawsze mogą zostać podzielone. Po tej operacji dane umieszczone są w jednym pliku MDB, natomiast część wykonywalna: formularze, raporty i moduły, w innym pliku. W jaki sposób zabezpieczyć taką aplikację. Przy obsłudze tabel połączonych należy utworzyć dwa zbiory uprawnień: jeden dla źródłowej bazy danych, a drugi dla jej klienta. Źródłem są tabele. W kliencie ustanowione są połączenia do tych tabel. Można ustawić uprawnienia do połączenia, ale nie ma to większego sensu. Połączenie jest niczym więcej jak zbiorem właściwości. Database=c:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb Wiedząc, że w tabeli połączonej przechowywanej na komputerze klienta nie ma żadnych danych, możesz nadać pełne prawa do tabeli połączonej. Takie postępowanie pozwala użytkownikom na odtworzenie definicji tabeli w razie potrzeby. Gdy połączenie nie jest chronione, należy zabezpieczyć źródłową bazę danych w normalny sposób. W ten sposób nierozpoznani użytkownicy nie będą mogli dostać się do danych innymi sposobami. Jeżeli będzie potrzeba odświeżenia połączeń do tabel źródłowych, możliwe są trzy sposoby: ? RefreshLink – wymagane prawo czytania danych w tabeli źródłowej. ? RefreshLink – wymagane prawo czytania projektu w tabeli źródłowej. ? Właściwość Connect – bez wymaganych praw w tabeli źródłowej. Jeżeli z bazy źródłowej zostaną usunięte wszystkie uprawnienia, trzecia możliwość jest jedyną możliwą. Opcje te muszą być uruchamiane poprzez DAO lub ADOX. Interfejs użytkownika nie pozwala na zarządzanie uprawnieniami połączenia, chyba że masz uprawnienia do czytania danych w bazie źródłowej. Można wykonać to w następujący sposób: Set tbldef = db.CreateTableDef(strTableName) With tbldef .SourceTableName=strTableName .Connect = ";Database=" & strTableName .Appedn tdf ' dołącz pojedynczą tabelę End With Innym sposobem poradzenia sobie z zagadnieniem połączeń jest całkowite usunięcie połączeń i dostęp do tabel źródłowych poprzez obiekt zdalnej bazy danych i wyrażenia SQL. Można również skorzystać z możliwości Accessa 2000 do związania formularza z odłączonym obiektem recordset. Na wydruku 23.1 znajduje się przykład tego podejścia. Wydruk 23.1. Wiązanie formularza z odłączonym obiektem recordset Dim wrk As Workspace Dim db As Database Dim rdb As Database Dim rs As Recordset Dim Connstr as String Set wrk = DBEngine.Workspaces(0) Set db = CurrentDb() Connstr = "C:\program files\microsoft office\" Connstr = Connstr & "office\samples\northwind.mdb" Set rdb = wrk.OpenDatabase(Connstr, , , "admin") Set rs = rdb.OpenRecordset("Select * from Customers") ... Łączenie tabel nie wpływa na ADOX poza jednym ważnym szczegółem, ADOX „nie interesuje się” obiektami umieszczonymi w bieżącej bazie danych (currentdb()), a więc nie zna uprawnień dotyczących połączenia. Przy użyciu ADOX dane są otwierane bezpośrednio w źródłowej bazie danych. Program na wydruku 23.2 otwiera połączenie ADO do źródła danych i ustawia uprawnienia dla użytkownika „JP”. Wydruk 23.2. Otwarcie bazy danych przez ADOX i nadanie uprawnień Dim cnn As New ADODB.Connection Dim cat As New ADOX.Catalog With cnn .Provider = "Microsoft.Jet.OLEDB.4.O" .ConnectionString = "data source=F:\NorthWind_Traders\& _ NorthWind.mdb;jet oledb:system database=" & "F:\NorthWind_Traders\sysnwind.mdw; " & "user id=Chuck;Password=opensesame" .Open End With Set cat.ActiveConnection = cnn cat.Users("JP").SetPermissions objName, adPermObjTable, _ adAccessGrant, adRightFull Opcja With OwnerAccess Jedną z możliwości jest usunięcie wszystkich uprawnień z tabel w bazie źródłowej. Można wtedy wykonywać kwerendy oparte na połączonych tabelach, używając klauzuli With OwnerAccess na końcu wyrażenia SQL lub ustawiając tę właściwość we właściwościach kwerendy. Tym sposobem kwerenda będzie mogła wykonać się i zwrócić wynik, jednak użytkownik nie będzie mógł zmienić danych ani struktury tabeli. Przykładowe wyrażenie SQL używające tej klauzuli wygląda następująco. SELECT Customers.* FROM Customers WITH OWNERACCESS OPTION Aby utworzyć zapytania wykorzystujące opcję With OwnerAccess, wykonaj następujące czynności: 132. Usuń wszystkie uprawnienia z tabel dla grup, które będą używać kwerendy. 133. Przy użyciu użytkownika, który ma prawo odczytaj dane i aktualizuj dane w tej tabeli (lub tabelach) utwórz zapytanie, wybierz kolumny i ustaw warunki, które określają oczekiwany wynik. 134. Zmień opcje uprawnień kwerendy na Właściciela. Pozwoli to na jej uruchomienie tak, jakby była uruchamiana przez użytkownika, ale tylko właściciel może wprowadzić do niej zmiany. Posiadanie zapytania, które może być zmieniane tylko przez właściciela, może przeszkadzać w złożonych aplikacjach, nad którymi pracuje więcej programistów. Najlepiej ustawić grupę jako właściciela kwerendy, co pozwoli na modyfikowanie jej przez wszystkich członków grupy, gdy zajdzie taka potrzeba. Powinieneś przestawić opcję uprawnień kwerendy na Użytkownika przed przeniesieniem właściwości kwerendy na grupę. Bezpieczeństwo systemu klient-serwer W czasie pracy z danymi umieszczonymi na serwerze np.: SQL Server, Oracle lub Sybase, te same serwery zabezpieczają dane, masz zwykle małą kontrolę nad tym systemem zabezpieczeń. Jeżeli Twoja aplikacja jest oparta o dane z tabel na serwerze i chcesz ograniczyć możliwość zapisu i wstawiania danych do tych tabel, możesz zrobić to poprzez uprawnienia Accessa, poprzez ADOX (użyj CurrentProject.Connection) lub używając interfejsu użytkownika. Zarządzanie użytkownikami System zabezpieczeń Jet jest oparty o użytkowników, jednak nie oznacza to, że musisz obsługiwać wiele szczegółów na jego temat. Zwykle wystarczy podać nazwę użytkownika, jego hasło i PID. Aby użytkownik mógł pracować, potrzebuje uprawnień, a aby można było łatwo zarządzać użytkownikami, powinien należeć do przynajmniej jednej grupy. Poza tym jest niewiele do zrobienia. Jeżeli wplączesz się w indywidualne ustawianie schematów zabezpieczeń dla poszczególnych użytkowników, stworzysz sam sobie problemy administracyjne. Po przypisaniu nazwy, PID i hasła, powinieneś modyfikować tylko hasło. Unikaj nadawania praw do obiektu użytkownikom. Zamiast tego nadawaj prawa do obiektów grupom, a następnie włącz użytkowników do tej grupy. Na wydruku 23.3 znajduje się prosta funkcja, która ilustruje, w jaki sposób sprawdzić, czy użytkownik istnieje, utworzyć go, usunąć, włączyć do grupy lub usunąć z grupy. Wydruk 23.3. Przykład funkcji sprawdzającej istnienie użytkownika, jego usuwanie i tworzenie Sub ADOXManageUser(strUserName, strPID, strPWD, _ ParamArray JoinGroups() As Variant) Dim cnn As New ADODB.Connection Dim cat As New ADOX.Catalog Dim Group As Variant With cnn .Provider = "Microsoft.Jet.OLEDB.4.O" .ConnectionString = "data source=C:\Program Files\ & _ Microsoft Office\Office\Samples\Northwind.mdb; & _ jet oledb:system database=C:\Program Files\ & _ Microsoft Office\Office\Samples\sysnwind.mdw; & user id=NWindAdmin;Password=opensesame" .Open End With Set cat.Active0onnection = cnn With cat ' Nie przewidujemy błędów On Error ReSume Next ' Sprawdź czy nazwa istnieje ' Jeżeli tak, usuń użytkownika ' Usunięcie użytkownika usuwa go również z wszystkich grup If strUserName = .Users(strUserName).Name Then .Users.Delete strUserName End If ' Utwórz nowego użytkownika .Users.Append strUserName, strPWD ' Gdy użytkownik istnieje, można dodać go ' do podanych grup For Each Group In JoinGroups() .Groups(Group).Users.Append strUserName Next ' Przed zakończeniem powinniśmy być zgodni z UI ' sprawdzam, czy użytkownik należy co najmniej do grupy ' Użytkownicy. Nie trzeba przeglądać wszystkich członków grupy ' wystarczy sprawdzić, czy nazwa występuje w kolekcji Users If Not strUserName = .Groups("Users").Users(strUserName).Name Then .Groups("Users").Users.Append strUserName End If End With End Sub Aby utworzyć lub zmienić użytkownika, funkcja wymaga jako argumentu nazwy użytkownika, jego PID i hasła oraz w tablicy parametrów listy grup, do których użytkownik powinien należeć. Funkcja sprawdza, czy nazwa użytkownika znajduje się w kolekcji Users. Jeżeli znajduje się tam, usuwa go i ponownie tworzy z nowym identyfikatorem PID. Następnie przegląda przez przekazaną tablicę parametrów i przypisuje użytkownika do grup. Aby być zgodnym z interfejsem użytkownika, funkcja sprawdza, czy użytkownik znajduje się co najmniej w domyślnej grupie Użytkownicy. Jeżeli grupa ta nie została wymieniona w parametrze, użytkownik zostanie do niej automatycznie przypisany. Wyliczanie grup i użytkowników oraz wyświetlanie przynależności Byłoby prawie niemożliwe administrowanie bazą danych, gdyby nie można było programowo uzyskać informacji, kto może używać bazy i w jakim stopniu jej używa. VBA Accessa pozwala poprzez ADOX pobrać listę wszystkich użytkowników z bazy danych, ich przynależność do grup oraz inne informacje. Przykład procedury wykonującej te czynności znajduje się na wydruku 23.4. Wydruk 23.4. Użycie ADOX do pobrania informacji o użytkownikach Public Sub ADOXGroupsandUsers() Dim cnn As New ADODB.Connection Dim cat As New ADOX.Catalog Dim i As Integer, k As Integer With cnn .Provider = "Microsoft.Jet.OLEDB.4.O" .ConnectionString = "data source=h:\books and articles\ & _ unleashed\securityexample.mdb; & _ jet oledb:system database=h:\books and articles\ & unleashed\sysnwind.mdw;user id=Admin;Password=letmein" .Open End With Set cat.ActiveConnection = cnn With cat Debug.Print ' Pobranie i wypisanie listy grup Debug.Print "Ilość grup = " & .Groups.Count For i = 0 To .Groups.Count - 1 Debug.Print " " & .Groups(i).name Next Debug.Print ' Pobranie i wypisanie listy użytkowników Debug.Print "Ilość użytkowników = " & .Users.Count For i = 0 To .Users.Count - 1 ' Nie pokazuj użytkowników 'Engine' i 'Creator' If .Users(i).Groups.Count > 0 Then Debug.Print " " & .Users(i).name End If Next Debug.Print 'Wypisz zawartość kolekcji Groups z katalogu wraz z ich członkami Debug.Print "Przynależność do grup" For i = 0 To .Groups.Count - 1 Debug.Print " " & .Groups(i).name For k = 0 To .Groups(i).Users.Count - 1 Debug.Print " " & .Groups(i).Users(k).name Next Next Debug.Print ' Wypisz zawartość kolekcji Users z katalogu ' wraz z przynależnością do grup Debug.Print "Przynależność użytkowników" For i = 0 To .Users.Count - 1 ' Nie pokazuj użytkowników 'Engine' i 'Creator' If .Users(i).Groups.Count > 0 Then Debug.Print " " & .Users(i).name For k = 0 To .Users(i).Groups.Count - 1 Debug.Print " " & .Users(i).Groups(k).name Next End.If Next End With End Sub Identyfikacja bieżących użytkowników za pomocą ADOX Często pojawiało się pytanie: „Kto jest teraz zalogowany” i do tej pory nie było eleganckiej metody sprawdzenia tego. Teraz za pomocą ADOX można użyć wykazu, aby sprawdzić, kto używa bazy danych w każdym momencie. Przykład tego znajduje się na wydruku 23.5. Wydruk 23.5. ADOX pozwala na sprawdzenie, kto używa bazy danych Sub UserRoster() ' Procedura używa rejestru użytkowników ' lub Jet 4.0, aby podłączyć się do bazy danych ' i sprawdzić, kto używa bazy danych Dim conn As ADODB.Connection Dim rst As ADODB.Recordset On Error GoTo Proc_Err Set conn = New ADODB.Connection 'Otwórz bazę źródłową With conn .Provider = "Microsoft.Jet.OLEDB.4.O" .ConnectionString = "data source=h:\books and articles\ & _ unleashed\securityexample.mdb; & _ jet oledb:system database=h:\books and articles\ & unleashed\sysnwind.mdw;user id=Admin;Password=letmein" .Open End With ' Otwórz recordset oparty na ilości użytkowników w bazie Set rst = conn.OpenSchema(adSchemaProviderSpecific, , "{947bb102-5d43-11d1-bdbf-00c04fb92675}") ' Dla każdego użytkownika wypisz nazwę komputera i inne dane Do Until rst.EOF Debug.Print rst!COMPUTER_NAME Debug.Print rst!LOGIN_NAME Debug.Print rst!CONNECTED Debug.Print rst!SUSPECTED STATE rst.MoveNext Loop Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Wyszukiwanie użytkowników z pustym hasłem Jedną z największych dziur w zabezpieczonej bazie danych jest użytkownik z pustym hasłem. Jet nie wymaga hasła, więc musi ono zostać wymuszone poprzez własne funkcje tworzenia użytkownika lub ktoś musi dla każdego użytkownika sprawdzić, czy można otworzyć bazę danych baz hasła. Funkcja na wydruku 23.6 przedstawia sposób, jak to zrobić przy użyciu ADOX. Wydruk 23.6. Wyszukiwanie pustych haseł Public Sub ADOXPasswordCheck() Dim strcnn1 As String Dim strcnn2 A5 String Dim cnn As New ADODB.Connection Dim pwrdtestcnn As New ADODB.Connection Dim cat As New ADOX.Catalog Dim pwdCat As New ADOX.Catalog Dim i As Integer, k As Integer Strcnn1 = "data source=C:\Program Files\Microsoft Office\Office\" Strcnn1 = strcnn1 & "Samples\NorthWind.mdb;" Strcnn1 = strcnn1 & "jet oledb:system database=" Strcnn1 = strcnn1 & "C:\Program Files\Microsoft Office\Office\" Strcnn1 = strcnn1 & "Samples\sysnwind.mdw; " Strcnn1 = strcnn1 & "user id=NWindAdmin;Password=OpenSaysaMe" With cnn .Provider = "Microsoft.Jet.OLEDB.4.O" .ConnectionString = strcnn1 .Open End With Set cat.ActiveConnection = cnn With cat For i = 0 To .Users.Count - 1 ' Nie pokazuj użytkowników 'Engine' i 'Creator' If .Users(i).Groups.Count > 0 Then ' Spróbuj otworzyć następne połączenie z nazwą użytkownika ' i pustym hasłem With pwrdtestcnn .Provider = cnn.Provider strcnn2="data source=C:\Program Files\" strcnn2= strcnn2 & "Microsoft Office\Office\Samples\" strcnn2= strcnn2 & "NorthWind.mdb; " strcnn2= strcnn2 & "jet oledb:system databa5e=" strcnn2= strcnn2 & "C:\Program Files\" strcnn2= strcnn2 & "Microsoft Office\Office\" strcnn2= strcnn2 & "Samples\sysnwind.mdw; strcnn2= strcnn2 & "user id=NWindAdmin;Password= " " .ConnectionString = strcnn2 ' Zwykle dostaniemy błąd, a nie chcemy, ' żeby nas zatrzymał On Error Resume Next .Open ' Brak błędu oznacza, że udała się próba wejścia bez hasła If Err = 0 Then ' użyj katalogu z bieżącego połączenia Set cat.ActiveConnection = pwrdtestenn Debug.Print cat.Users(i).name & " nie ma hasła" ' Zamknij to połączenie pwrdtestcnn.Close End If End With End If Next End With End Sub Ustawianie i usuwanie hasła Ustawienie lub usunięcie hasła można wykonać przy użyciu interfejsu użytkownika lub poprzez ADOX. Poniższy wiersz kodu zmienia hasło. Cat.Users("Admin").changepassword "StareHasło", "NoweHasło" Ustawienie obu argumentów metody changepassword na puste ciągi znaków usuwa hasło. Mimo że członek grupy Administratorzy nie może zobaczyć hasła innego użytkownika, może on usunąć dowolne hasło. Zarządzanie grupami Aby łatwiej zarządzać użytkownikami, możesz przypisać uprawnienia i właściwość obiektu do grup zamiast do użytkowników. Ogranicza to ilość różnych profili uprawnień. Zarządzanie właściwością obiektów Aby posiadać pełną kontrolę nad obiektami, powinieneś wiedzieć, w jaki sposób dostać się i zmodyfikować właściciela obiektu. Na wydruku 23.7 przedstawione jest, jak dowiedzieć się, do której grupy należy obiekt i zmienić właściciela na grupę, co ułatwi administrację. Wydruk 23.7. Przypisywanie właściciela obiektu Public Sub ADOXGroupOwnership(strObjectName As String, strGroupName As String) Dim cat As New ADOX.Catalog Dim n As 5tring ' Tutaj pracujemy na komputerze klienta, ale jeżeli chcesz pracować z innym ' plikiem MDB, po prostu utwórz i otwórz połączenie do niego Set cat.ActiveConnection = CurrentProject.Connection With cat Debug.Print .GetObjectOwner(strObjectName, adPermObjTable) .SetObjectOwner strObjectName, adPermObjTable, strGroupName .Tables.Refresh Debug.Print .GetObjectOwner(strObjectName, adPermObjTable) cat.Tables.Refresh End With End Sub Zarządzanie wieloma aplikacjami Przy użyciu ADOX Twoja aplikacja nie ładuje DDL lub zabezpieczeń, jeżeli tego nie potrzebuje, i ładuje, gdy tego potrzebuje. ADOX znajduje się w niewielkiej bibliotece (msadox.dll) z jasnym i uniwersalnym interfejsem programowym. Mimo że ADOX wciąż posiadał, w czasie pisania tej książki, kilka usterek, ale także posiada duży potencjał. Za jego pomocą można administrować wszystkimi widocznymi grupami roboczymi z jednego miejsca. Nie wydaje się być to niczym nowym, ale gdy rozważysz możliwość koordynowania zabezpieczeń Oracle i SQL Server oraz definicji danych w Twojej lokalnej grupie roboczej, jest to imponujące. W chwili obecnej możesz wykonywać instrukcje DDL dla Oracle, używając dostawcy MSDAORA i ADOX. Gdy spotykasz się z implementacją systemu bezpieczeństwa oraz zagadnieniami definicji danych w wielu aplikacjach, zwróć uwagę na ADOX i sprawdź, czy spełni wszystkie oczekiwania. Właścicielem obiektów w bazie danych powinna być grupa. Strategia ta sprawdza się również w przypadku zarządzania wieloma aplikacjami. ADOX pozwala na zarządzanie systemem bezpieczeństwa oraz wykonywanie poleceń DDL dla wielu aplikacji z jednego miejsca, tym bardziej ważne jest przypisanie grupy jako właściciela wszystkich obiektów. Ułatwia to również rozwój aplikacji. Jeżeli właścicielem obiektu jest pojedynczy użytkownik, tylko on może wprowadzić do niego poprawki. W przypadku, gdy właściciel nie jest osiągalny, proces rozwoju aplikacji poważnie zwalnia. Zamiast czekać na tę sytuację, lepiej skorzystaj z grupy jako właściciela obiektów. Tym sposobem każdy członek grupy może wprowadzić niezbędne poprawki. Różne aplikacje mogą posiadać wspólną grupę roboczą (rysunek 23.1). Korzystaj z tej możliwości kiedykolwiek tylko możesz. Istnieje duża szansa, że większość grup w różnych aplikacjach jest identyczna. Zmniejsza to ilość pracy dla administratora. Jeżeli jest to możliwe, staraj się, aby użytkownicy korzystali ze wspólnych plików, zamiast tworzyć schemat replikacji. Mimo że replikacja jest świetnym narzędziem na współdzielenie danych i daje wiele możliwości dla aplikacji Accessa, jednak pociąga ona zwykle duże koszty administracyjne. Kluczem do zarządzania wieloma aplikacjami jest współdzielenie obiektów, użytkowników, grup, grup roboczych i katalogów, gdziekolwiek jest to tylko możliwe. Zmniejszenie liczby zmiennych przy utrzymaniu tych aplikacji spowoduje, że będą bardziej niezawodne i solidne. Użycie SQL Access 2000 dostarcza nowego sposobu obsługi podstawowych możliwości systemu zabezpieczeń w bazie danych oraz w kliencie. Do dialektu SQL zostały dodane nowe słowa kluczowe, które pozwalają na tworzenie użytkowników i grup, dodawanie użytkowników do grup, usuwanie użytkowników i grup, przypisywanie uprawnień oraz ich odbieranie. Wyrażenia takie są wykonywane identycznie jak inne wyrażenia SQL, jednak zamiast zwrócić wynik lub zmienić definicję bazy danych, wpływają na ustawienia zabezpieczeń wymienionych obiektów. Create Create User i Create Group wykonują dokładnie to, czego można się spodziewać. Do kolekcji użytkowników lub grup w pliku systemowym bazy danych dodawany jest nowy użytkownik lub grupa. Jedyną różnicą pomiędzy tym sposobem a użyciem ADOX jest brak identyfikatora PID. W wyrażeniu SQL nie można używać identyfikatora PID. Poniżej znajduje się przykład tworzenia użytkownika i grupy za pomocą wyrażeń SQL. CREATE USER użytkownik hasło [,użytkownik hasło, ...] CREATE GROUP grupa hasło [,grupa hasło, ...] Po utworzeniu użytkowników i grup można dodać użytkownika do grupy za pomocą wyrażenia Add User. Add User Add User wpływa również na kolekcję grup w pliku grupy roboczej. Gdziekolwiek występuje odwołanie do pliku grupy roboczej, dotyczy bieżącej grupy. Za pomocą SQL nie można zmieniać innego pliku grupy roboczej niż ten, do którego jest zalogowany użytkownik. ADD USER użytkownik [, użytkownik, ...] TO grupa Grant/Revoke Po utworzeniu użytkowników i dodaniu ich do grup można nadać im uprawnienia. Wyrażenie Grant pozwala na nadanie przywileju do obiektu użytkownikowi lub grupie. GRANT {prawo [, prawo, ...]} ON {TABLE tabela | INDEX indeks | QUERY kwerenda | CONTAINER} TO {użytkownik/grupa [,użytkownik/grupa, ...]} Za pomocą tej metody możesz nadać mniej uprawnień niż za pomocą ADOX. Uprawnienia, które możesz nadać, są następujące: Select Selectsecurity Create Delete Updatesecurity Selectschema Insert Dbpassword Schema Update Updateidentity Updateowner Drop Za pomocą SQL można nadawać uprawnienia do tabel, indeksów, kwerend i kontenerów. Po nadaniu uprawnień można je odebrać za pomocą odwrotnego do Grant wyrażenia Revoke. Składnia i opcje są identyczne jak dla wyrażenia Grant, a rezultat dokładnie odwrotny. Drop Po usunięciu uprawnień możesz usunąć użytkownika za pomocą wyrażenia Drop. Składnia i opcje są identyczne jak dla wyrażenia Create poza słowem kluczowym Drop. Wynikiem wyrażenia jest usunięcie użytkownika lub grupy z pliku grupy roboczej. Zabezpieczanie bazy danych krok po kroku Dobrze jest wiedzieć, że mimo oszałamiającej liczby opcji i nowych funkcji podstawowe czynności przy zabezpieczaniu bazy danych Accessa nie zmieniły się. Jeżeli podczas implementowania systemu bezpieczeństwa wykonasz możliwie dokładnie poniższe kroki, w pełni wykorzystasz możliwości ochrony Accessa. Niedotrzymanie któregoś z punktów może spowodować obniżenie poziomu bezpieczeństwa. 135. Utwórz nową grupę roboczą. Użyj programu wrkgadm.exe opisanego na początku tego rozdziału. Wybierz opcję tworzenia nowego pliku grupy roboczej. 136. Otwórz Accessa, używając pliku grupy roboczej utworzonego specjalnie dla Twojej aplikacji. 137. Otwórz lub utwórz bazę danych, którą chcesz zabezpieczyć. 138. Utwórz nowego użytkownika i dodaj go do grupy Administratorzy. 139. Zmień hasło użytkownika Administrator. 140. Usuń wszystkie uprawnienia dla grupy Użytkownicy z wszystkich obiektów w bazie danych. 141. Zamknij bazę danych. 142. Otwórz Accessa, logując się jako nowy administrator. 143. Otwórz bazę danych, którą chcesz zabezpieczać. 144. Uruchom kreatora zabezpieczania na bazie danych. Zaoszczędzi Ci wiele żmudnej pracy, zmieniając właściciela obiektów. 145. Usuń użytkownika Administrator z grupy Administratorzy. 146. Utwórz użytkowników i grupy potrzebne w aplikacji. 147. Przypisz użytkowników do odpowiednich grup. 148. Ustaw odpowiednie uprawnienia dla grup. 149. Dodawaj i usuwaj grupowe uprawnienia, tak jak tego potrzebujesz. Częste błędy bezpieczeństwa Jeden z częstych problemów występuje, gdy użytkownik logując się do jednej grupy roboczej może wejść do innej bazy danych na użytkownika Administrator. Zwykle dzieje się to, ponieważ system bezpieczeństwa został utworzony w domyślnym pliku system.mdw. Systemowy plik MDW nie jest zabezpieczony i nigdy nie może być zabezpieczony, ponieważ przy jego tworzeniu nie został podany PID. Ponieważ użytkownik Administrator jest uniwersalny, ktokolwiek może dostać się do takiego systemu. Jest również możliwe, że użytkownik Administrator nie został usunięty z grupy Administratorzy. Ponieważ użytkownik Administrator nie jest unikatowy dla wszystkich grup roboczych, każda z nich będzie widziała użytkownika Administrator jako swojego Administratora. Jeżeli w Twojej grupie Administrator będzie członkiem grupy Administratorzy, użytkownicy z innych grup roboczych będą mogli zalogować się do Twojej grupy z pełnymi prawami. Aby rozwiązać ten problem, musisz zabezpieczyć bazę danych z użyciem nowego pliku grupy roboczej. Czasami baza danych wydaje się zabezpieczona, wszyscy mogą się zalogować, ale nie działają uprawnienia. Zwykle jest to spowodowane pozostawieniem uprawnień w grupie Użytkownicy. Po utworzeniu wszystkie grupy robocze dają użytkownikom pełne prawa dostępu do wszystkich obiektów w bazie danych. Wszyscy użytkownicy są domyślnie w grupie Użytkownicy. Nawet gdy nie nadasz praw administratora, wszyscy użytkownicy z grupy Użytkownicy odziedziczą je z grupy. Upewnij się, że usunąłeś wszystkie uprawnienia z grupy Użytkownicy. Nic nie ogranicza Cię w tworzeniu tylu grup, ile potrzebujesz. Ponieważ grupa Użytkownicy jest bezużyteczna z powodu braku uprawnień, a Administratorzy jest zbyt potężna, nie masz wyboru i musisz opracować swój schemat bezpieczeństwa i utworzyć grupy w nim przewidziane. Część VIII Publikowanie w sieci za pomocą Accessa 2000 W tej części: ? Konfiguracja serwera WWW dla publikowania w sieci WWW. ? Przenoszenie Accessa 2000 do sieci WWW. ? Użycie stron dostępu do danych. ? Publikowanie w sieci przy użyciu Accessa 2000 i Active Server Pages. Rozdział 24. Konfiguracja serwera WWW dla publikowania w sieci WWW W tym rozdziale: ? Środowisko programistyczne a środowisko produkcyjne. ? Wybór platformy. ? Co to jest Option Pack. ? Uruchomienie serwera WWW. ? Zarządzanie i konfiguracja serwera WWW. ? Zabezpieczanie aplikacji WWW. ? Różnice pomiędzy witryną a katalogiem wirtualnym. Większość programistów Accessa czuje się bardzo niepewnie, gdy ich szef lub klienci wspominają o publikowaniu w sieci za pomocą Accessa 2000, ponieważ większość z nich jest ekspertami w zarządzaniu bazą danych oraz VBA, natomiast niewiele wiedzą na temat uruchamiania i utrzymywania serwera WWW. W tym rozdziale wyjaśnimy, jak skonfigurować komputer do programowania dla sieci WWW, jak uaktualniać serwer WWW i jak używać technologii serwera WWW Microsoft. Nie znaczy to, że po zapoznaniu się z tym rozdziałem będziesz administratorem serwera WWW, ale w razie potrzeby będziesz potrafił uruchomić serwer WWW. Środowisko programistyczne a środowisko produkcyjne Należy uściślić terminologię, której będziemy używać w tej części książki. Podczas tworzenia projektu wystąpią prawdopodobnie dwa różne środowiska: środowisko programistyczne i środowisko produkcyjne. Środowisko programistyczne jest miejscem, w którym tworzysz aplikację. Środowisko produkcyjne jest miejscem, gdzie Twoja aplikacja będzie umieszczona po jej ukończeniu. Jeżeli tworzysz strony na komputerze z Windows 95, a umieszczasz je na komputerze z Windows NT Server w celu ich przetestowania i wykrycia błędów, komputer Windows 95 jest Twoją maszyną programistyczną, natomiast Windows NT Server jest środowiskiem produkcyjnym. W idealnym przypadku, Twoje środowisko programistyczne i produkcyjne powinny mieć identyczne konfiguracje sprzętowe i programowe, ale powinny znajdować się na oddzielnych komputerach. Zwykle nie jest to osiągalne. Wielu ludzi (włączając niektórych autorów tej książki) używa Windows 95/98 lub Windows NT Workstation jako ich środowisko programistyczne, natomiast umieszczają pliki na komputerze Windows NT Server, który jest ich środowiskiem produkcyjnym. Wspaniałą możliwością technologii WWW Microsoft jest możliwość tworzenia i testowania aplikacji WWW Accessa 2000 na komputerze z Windows 95/98 i umieszczanie ich na Windows 2000/NT 4.0 bez żadnych zmian. Microsoft dostarcza jednej technologii WWW, która działa na każdym ze wspomnianych systemów operacyjnych. Aby skorzystać tej technologii, należy zainstalować serwer WWW na Twoich komputerach roboczym i produkcyjnym. Wybór platformy Microsoft wypuścił trzy różne aplikacje serwera WWW, po jednej na każdy poziom platformy Windows. Pierwszy z nich, Personal Web Server 4.0 (PWS4), działa na Windows 95/98 i dostarcza podstawowych funkcji serwera WWW. Kolejny, Peer Web Services (znów PWS4), jest również serwerem o ograniczonych możliwościach prawie identycznych z wersją dla Windows 95/98, ale zmodyfikowany do pracy w Windows NT 4.0 Workstation. Ostatni, Internet Information Server 4.0 (IIS4), może pracować na Windows NT 4.0. Wersje działające na Windows 95/98 mają tak podobne możliwości i funkcje, że w dalszej części książki będę je nazywał PWS, bez rozróżniania tych dwóch produktów. Wybranymi funkcjami tych dwóch produktów są: ? Możliwość udostępniania prostych stron WWW. ? Możliwość tworzenia aplikacji Active Server Pages. ? Możliwość tworzenia transakcyjnych aplikacji WWW za pośrednictwem Microsoft Trasaction Server. ? Obsługa połączeń ODBC. ? Możliwość użycia komponentów dostępu do danych: Microsoft Data Access Components (MDAC). ? Microsoft Message Queue (MSMQ). W czasie instalacji Option Pack instalowane są komponenty Microsoft Data Access Components w wersji 1.5. Zaleca się zainstalowanie najnowszej wersji tych komponentów. W czasie pisania tej książki dostępną były MDAC 2.1 instalowane razem z Accessem 2000. Powinieneś również wiedzieć, że istnieje różnica pomiędzy wersjami MSMQ, instalowanymi z Option Pack, w zależności od systemu operacyjnego. MSMQ instalowane na Windows NT Server jest w pełni funkcjonalną usługą kolejki komunikatów, natomiast wersja dla Windows NT Workstation i Windows 95/98 są po prostu klientami używającymi usługi MSMQ na serwerze. Mimo wielu podobieństw występują również różnice, w większości mające związek z wydajnością i skalowalnością. Powinny być one brane pod uwagę przy wyborze docelowej platformy produkcyjnej. Personal Web Server i Peer Web Services Personal Web Server i Peer Web Services są wspaniałymi narzędziami do tworzenia aplikacji lokalnie na swoim komputerze, bez potrzeby korzystania z NT Server. Pozwalają na tworzenie i testowanie aplikacji przed wypuszczeniem jej do produkcyjnego serwera WWW. Jeżeli aplikacja działa prawidłowo na PWS, masz zapewnione, że będzie działała po przeniesieniu jej na IIS4. Ponieważ PWS nie został zaprojektowany do obsługi obszernych witryn WWW, brak w nim niektórych funkcji zawartych w IIS4, takich jak Index Server, SMTP Server oraz Certificate Server. Istnieje również ograniczenie ilości jednocześnie przyłączonych klientów, tylko jedno w przypadku Windows 95/98 i nie więcej jak 10 dla Windows NT Workstation. Internet Information Server Internet Information Server 4.0 jest dużo wydajniejszym serwerem WWW niż Personal Web Server. Jest to zalecana platforma dla wszystkich produkcyjnych serwerów WWW, ponieważ lepiej wytrzymuje duże obciążenie. Powinieneś zauważyć lepsze osiągi IIS4 w porównaniu z PWS4. IIS4 nie posiada ograniczeń na ilość jednocześnie podłączonych użytkowników. W zależności od projektu Twojej aplikacji może potencjalnie obsłużyć tysiące równoległych użytkowników. Instalacja obu produktów jest bardzo łatwa i dosyć podobna. Zaleca się instalowanie tylko tych usług, które będziemy wykorzystywali. Załadowanie niepotrzebnych komponentów powoduje niepotrzebne obciążenie stacji roboczej lub serwera. Teraz po zapoznaniu się z podstawowymi faktami na temat dostępnych serwerów WWW należy odpowiedzieć na pytanie, którego należy użyć? Powinieneś w razie możliwości używać IIS4 i Windows NT 4 Server dla środowiska produkcyjnego. Będziesz lepiej wyposażony do tworzenia aplikacji, mając jako swoje środowisko programistyczne maksymalnie podobne do docelowego środowiska produkcyjnego. Zalecam więc IIS4 i NT Server jako środowisko programistyczne. Prawie każda aplikacja Active Server Pages, jaką napiszesz, będzie działała na dowolnej platformie WWW: IIS4 lub PWS. Aby zainstalować serwer Microsoft Web, należy zainstalować NT 4.0 Option Pack. Pomiędzy ASP działającymi na IIS3 i IIS4 występują różnice. IIS3 używa VBScript 2, natomiast IIS4 używa VBScript 3. Wszystkie wersje VBScript są ze sobą zgodne w tył, natomiast każda nowa ma nowe funkcje. Musisz być ostrożny, wymagając nowszych funkcji, chyba że jesteś pewien, że Twój serwer WWW już je obsługuje. Jeżeli masz zainstalowany Internet Explorer 5 na serwerze, posiadasz VBScript 5, który zawiera wszystkie wcześniejsze funkcje oraz dodatkowe zalety. Jeżeli nie masz zainstalowanego w Twoim systemie Internet Explorer 5, a chcesz skorzystać z zalet najnowszej maszyny skryptowej, możesz załadować najnowszą wersję z www.miscrosoft.com/scripting/. Dwie nowe funkcje wprowadzone w wersji 5 to Eval i Execute, pozwalające na tworzenie kodu w czasie jego pracy. Wprowadzono kilka zmian polepszających wydajność aplikacji używających VBScript (włączając w to Active Server Pages). Co to jest Option Pack Jedynie standardowa instalacja Windows 2000 zawiera wszystkie niezbędne pliki do tworzenia aplikacji dla WWW, natomiast usługi Web są bezpłatnym dodatkiem do NT 4.0 i Windows 95/98. Windows NT Option Pack jest pakietem, który dostarcza funkcji niezbędnych do programowania dla WWW i publikowania w Sieci. Mimo że nazywa się „Windows NT” Option Pack, ten sam pakiet instalacyjny może być użyty do zainstalowania Personal Web Server 4 i innych rozszerzeń sieciowych do Windows 95/98. W trakcie instalacji NT Server 4.0, masz możliwość zainstalowania Internet Information Server (wersja 2), jednak nie zapewnia on wymaganych możliwości do tworzenia Active Server Pages, która jest kluczową technologią Microsoftu i tematem rozdziału 27. „Publikacja w sieci WWW za pomocą Access 2000 i Active Server Pages”. Teraz, gdy jesteśmy przy tym temacie, nie zalecamy instalowania IIS podczas instalacji Windows NT Server lub odinstalowania go przed dalszą pracą. Zawsze lepiej jest rozpocząć od czystej instalacji niż od aktualizacji. Najnowsza wersja serwera WWW wchodzi w skład Option Pack, który można otrzymać z wielu źródeł. Jeżeli prenumerujesz MSDN, jest on do Ciebie automatycznie rozsyłany. Możesz również kupić płytę CD-ROM lub załadować go z serwera WWW Microsoftu. Option Pack dostępny jest pod adresem: http://www.microsoft.com/ntserver/nts/downloads/recommended/NT40ptPk/default.asp. Option Pack może zostać zainstalowany i uruchomiony na Windows 95/98, Windows NT Workstation oraz Windows NT Server 4.0. Przed zainstalowaniem Option Pack powinieneś zainstalować Microsoft Internet Explorer 4.0 lub nowszy. Zalecamy zainstalowanie najnowszej wersji przeglądarki, która posiada większość łatek i poprawek (w chwili pisania książki jest to Internet Explorer umieszczony na dysku z Office 2000). Dodatkowo, jeżeli instalujesz Option Pack na komputerze z Windows NT 4.0, musisz mieć zainstalowany Service Pack 3. Service Pack 4 jest najnowszym pakietem poprawek dla Windows NT dostarczonym przez Microsoft, ale powinien być zainstalowany PO zainstalowaniu Option Pack. Jeżeli z jakiegoś powodu musisz przeinstalować Service Pack 3 po instalacji Option Pack, nie nadpisuj żadnych nowszych plików zainstalowanych przez Option Pack. Przed instalacją Microsoft Option Pack powinieneś się upewnić, że twój komputer spełnia wymagania podane w tabeli 24.1. Tabela 24.1. Minimalne wymagania sprzętowe dla instalacji dla Windows NT Option Pack Komponent sprzętu Wymagane Zalecane Procesor 66 MHz 486 90 Mhz Pentium RAM 32 MB 64 MB Wolne miejsce na dysku 30 MB 100 MB Monitor VGA Super VGA CD-ROM (niewymagany) 3x 6x Uruchomienie serwera WWW Serwery WWW mogą być, w zależności od potrzeb Twojej aplikacji, proste lub skomplikowane. Powodem dużego skomplikowania jest możliwość całkowitej kontroli, jaką możesz mieć przy użyciu serwerów WWW firmy Microsoft. Instalacja Przed zainstalowaniem Option Pack muszą być spełnione wymagania określone wcześniej, takie jak: instalacja Internet Explorer 4.01 i Service Pack 3 (w przypadku NT). W czasie instalacji NT Option Pack musisz spełnić kilka wymagań, aby móc tworzyć aplikacje przy użyciu Office 2000. Instalacja wielu z proponowanych komponentów jest zbędna, jeżeli zaakceptujesz domyślne wartości. W tej części rozdziału wymienimy dostępne opcje instalacji, opcje, których zainstalowanie jest niezbędne oraz komponenty, które powinieneś zainstalować nawet, gdy tylko planujesz ich użycia. NT Option Pack dla Windows 95/98 Komponenty dostępne w czasie instalacji NT Option Pack różnią się w zależności od platformy, na jaką instalujesz pakiet. Dostępne komponenty instalacji Poniżej wymienione zostały komponenty dostępne w czasie instalacji, gdy po uruchomieniu programu instalacyjnego wybierzesz Custom Installation. Opcje wymagane przez konkretny system operacyjny zostały odpowiednio opisane. Zaznaczone zostały również komponenty niezbędne do tworzenia aplikacji WWW przy użyciu Office 2000, Active Server Pages oraz obiektów COM. ? Certificate Server (tylko NT Server). Pozwala na tworzenie i wysyłanie certyfikatów cyfrowych. Możliwości te pozwalają na uruchomienie w aplikacjach dodatkowej warstwy zabezpieczeń. Można utworzyć osobisty certyfikat bezpieczeństwa dla klienta, który ładuje ten certyfikat do komputera i instaluje w oprogramowaniu klienta (w przeglądarce). W przyszłości możesz upewnić się, że klient jest tym, za kogo się podaje. ? Option Pack Common Program Files. Zawiera pliki wspólne dla większości komponentów. Są one wymagane, aby tworzyć aplikacje dla WWW. ? FrontPage 98 Server Extensions. Umożliwia tworzenie witryn i wykonanie podstawowych czynności administracyjnych za pomocą Microsoft FrontPage i Microsoft Visual InterDev. Nie musisz instalować tego komponentu, chyba że chcesz używać FrontPage lub Visual InterDev do tworzenia aplikacji. Można używać ograniczonej ilości funkcji tworzenia aplikacji przy użyciu FrontPage bez instalowania rozszerzeń FrontPage, ale nie będzie można korzystać z wbudowanych kreatorów, robotów WWW i funkcji publikacji. Ponieważ rozszerzenia te powodują pewien narzut na serwerze, wielu programistów używa tych narzędzi do tworzenia szkieletu kodu, który jest modyfikowany przez inne narzędzia i następnie przenoszony na serwer za pomocą standardowego oprogramowania FTP. ? Internet Connection Services for RAS. Zarządza wieloma połączeniami wdzwanianymi oraz książkami telefonicznymi. Pakiet ten nie jest wymagany. ? Microsoft Data Access Component 1.5. Instalowane są komponenty ActiveX Data Components 1.5 (ADO) oraz komponenty Remote Data Services (RDS). W komputerze umieszczane są sterowniki i dostawcy, które umożliwiają połączenie do baz danych. Jest to komponent niezbędny do tworzenia aplikacji WWW Office 2000. Po zainstalowaniu tego komponentu powinno się zainstalować najnowszą wersję komponentów MDAC (wersja 2.1). Od czasu wypuszczenia Option Pack pojawiło się kilka kolejnych wydań pozbawionych zauważonych błędów i zawierających dodatkowe funkcje wymagane przy tworzeniu aplikacji Office 2000 (sieciowych i innych). ? Microsoft Message Queue (MSMQ). Pozwala aplikacjom na przesyłanie informacji o transakcjach do innych komponentów bez potrzeby czekania na odpowiedź. Funkcja ta powinna być zbadana, jeżeli tworzysz aplikacje transakcyjne, a interfejsy, których używasz, są czasami niepewne. Przykładowo, jeżeli używasz MSMQ i wystąpi chwilowa przerwa w połączeniu sieciowym, MSMQ będzie próbował dokończyć transakcję. Gdy przerwa w sieci zostanie usunięta, transakcja może zostać zatwierdzona. Nie jest to wymagana funkcja, chyba że masz specjalne wymagania i planujesz użyć tej usługi w aplikacjach. ? Personal Web Server (tylko Windows 95/98 i Windows NT Workstation). Komponent ten zawiera właściwą część usługi WWW. Jest on wymagany, jeżeli planujesz testować aplikacje na Twoim komputerze. ? Internet Information Server (tylko Windows NT Server). Pakiet zawiera: ? Usługę File Transfer Protocol (FTP); ? Usługę NNTP (do utrzymywania grup dyskusyjnych) ? Internet Service Manager (ISM). Jest to komponent wymagany do administracji i konfiguracji usługi WWW poprzez Microsoft Management Console. ? Usługę Simple Mail Transfer Protocol (SMTP). Pozwala na generowanie przesyłek e-mail z aplikacji i wysyłania ich do adresatów. ? World Wide Web Server (usługa HTTP). Jest niezbędna, jeżeli chcesz tworzyć, testować i udostępniać aplikacje WWW na Twoim serwerze. ? Przykładowa witryna WWW. Jeżeli rozpoczynasz programowanie dla WWW, powinieneś zainstalować te przykłady, aby zapoznać się z użytymi konwencjami programowania i użytymi technikami. ? ISM w wersji HTML (Internet Service Manager). Pozwala on na zdalną administrację serwerem WWW poprzez interfejs HTML. ? Microsoft Transaction Server 2.0 (MTS). Instaluje administratora COM i DCOM. Jest wymagany przy programowaniu dla WWW. ? Microsoft Index Server (tylko NT Server). Pozwala na przeszukiwanie tekstu dokumentów umieszczonych na serwerze WWW. Jest to świetne narzędzie do wyszukiwania zawierające wiele zaawansowanych funkcji. Jeżeli go zainstalujesz, upewnij się, że go używasz. Uruchomienie procesu indeksowania wszystkich Twoich stron WWW może być bardzo kosztowne. Nie jest to konieczna dla nas opcja. ? Microsoft Script Debugger (tylko NT Server). Pozwala na uruchamianie skryptów ASP. Może być użyty do ułatwienia uruchamiania skryptów ASP. Jest automatycznie uruchamiany w razie wystąpienia błędu. Ze względów wydajności i bezpieczeństwa nie powinien być instalowany na produkcyjnym serwerze WWW. Nie jest konieczny do programowania z Office 2000. ? Windows Scripting Host. Pozwala na pisanie i uruchamianie lokalnych plików skryptów, które mogą wykonywać niektóre funkcje administracji systemem. Nie jest konieczny do programowania z Office 2000. ? Microsoft Management Console (tylko Windows NT). Główne narzędzie w Windows NT, służące do zarządzania i konfiguracji wszystkich usług zainstalowanych przez Option Pack. Jest to wymagany komponent w przypadku Windows NT Server. Nie jest wymagany w przypadku NT Workstation (można użyć Personal Web Manager), ale jest rekomendowany. ? Visual InterDev RAD Support. Pozwala aplikacjom Visual InterDev na zdalne rozpowszechnianie aplikacji na Twój serwer. Nie jest to wymagana opcja przy programowaniu w Office 2000. Instalowanie Visual InterDev RAD Support powoduje potencjalne osłabienie systemu bezpieczeństwa twojego systemu, więc powinieneś być ostrożny. Komponent ten pozwala na zdalne rozsyłanie aplikacji, nawet bez Twojej wiedzy. Tak jak w przypadku platformy programistycznej możliwe jest, że komponent zdalnie zainstalowany na Twoim komputerze będzie miał niesprzyjające efekty w Twoim systemie. Jak widać, w NT Option Pack umieszczono wiele składników. Każdy z tych składników dodaje kolejne możliwości, ale nie są one wymagane do podstawowego programowania dla WWW i mogą wnosić niepotrzebny narzut w systemie, jeżeli są zainstalowane bez powodu. Aby ułatwić instalacje NT Option Pack, Microsoft dołączył do programu instalacyjnego trzy prekonfigurowane opcje instalacji. Komponenty instalowane przez te opcje są przedstawione poniżej. Opcje instalacji: minimalna, typowa i niestandardowa Jeżeli wybierzesz instalację niestandardową (custom), będziesz mógł wybrać dowolne składniki z listy, którą przedstawiliśmy powyżej. Nie jest to zwykle potrzebne lub wymagane, więc Microsoft dał możliwość skorzystania z dwóch innych opcji. Instalacja minimalna zawiera wszystko, co jest niezbędne do tworzenia podstawowych aplikacji WWW za pomocą Office 2000. Podczas instalacji w Twoim komputerze znajdą się następujące komponenty: ? Microsoft Data Access Components 1.5; ? Personal Web Server (tylko Windows 95/98 lub NT Workstation); ? Internet Information Server (tylko NT Server); ? Transaction Server; ? SMTP Service (tylko NT Server). Instalacja typowa zawiera wszystkie komponenty wymienione powyżej oraz dodatkowo: ? FrontPage Server Extensions; ? Dokumentacja do Personal Web Server (tylko Windows 95/98 i NT Workstation); ? Dokumentacja do Internet Information Server (tylko NT Server); ? Dodatkowa dokumentacja do: Active Server Pages, usługi SMTP, ADO oraz Index Server (tylko NT Server); ? Microsoft Index Server (tylko NT Server); ? Microsoft Management Console (tylko NT Server); ? Index Server (tylko NT Server); ? Microsoft Script Debugger; ? Windows Scripting Host. Aby wykonać pełną instalację dokumentacji do Active Server Pages dla Personal Web Server, musisz uruchomić instalację niestandardową i włączyć ten składnik instalacji. Z jakiegoś powodu Microsoft zdecydował się nie włączać tego składnika do żadnej z dwóch przygotowanych opcji instalacji. Jeżeli potrzebujesz jakiegoś zaawansowanego komponentu, który nie instaluje się automatycznie, powinieneś uruchomić instalację niestandardową. Jeden z przedstawionych wcześniej komponentów, Microsoft Transaction Server, jest tak ważnym usprawnieniem i integralną częścią strategii WWW firmy Microsoft, że zdecydowaliśmy się omówić go bardziej szczegółowo w następnej części tego rozdziału. Microsoft Transaction Server 2.0 Microsoft Transaction Server (MTS) jest jednym z ważniejszych składników Option Pack i jest niezbędny do pracy wielu innych usług, włączając w to IIS/PWS. MTS jest brokerem wywołań obiektów (object request broker) oraz brokerem transakcji (transaction broker). Do tej pory krytyczne aplikacje musiały pracować na wielkich systemach zaopatrzonych w specjalne oprogramowanie zapewniające wymaganą niezawodność. MTS jest tak ważny dla pracy IIS, że Microsoft umieścił go jako część Windows 2000 i zmienił jego nazwę na COM+. MTS jest niezbędny do instalacji usług WWW Microsoftu, ponieważ nawet gdy jawnie nie używałeś w aplikacji WWW tego składnika, MTS zarządza wszystkimi aplikacjami ASP. Każda przetwarzana strona ASP jest wykonywana przez MTS (zarządzający ASP.DLL). Jest to powód, dlaczego IIS4 ma tak ogromną wydajność w porównaniu do IIS3. Co to jest broker transakcji? Dobre pytanie. Broker transakcji zarządza transakcjami, jednak to stwierdzenie również nie mówi zbyt wiele. Większość systemów baz danych, jak Microsoft SQL Server, zapewnia zarządzanie transakcjami. Serwer bazy danych rozpoczyna transakcję, a następnie wykonywane jest jedno lub więcej wyrażeń SQL na jednej lub więcej tabelach. Serwer bazy danych nie zatwierdza zmian, dopóki nie dostanie polecenia mówiącego, że wszystko się udało. Pomaga to na zachowanie integralności danych w bazie danych i spójności w aplikacji. Zapewnia to, że wyrażenie 1 zostanie wykonane tylko razem z wyrażeniem 2 i 3. Jeżeli transakcja nie powiodła się, jest ona wycofywana, co oznacza, że wszystkie wyrażenia SQL są anulowane i baza danych jest przywrócona do stanu sprzed transakcji. MTS zapewnia dla obiektów COM to samo co serwer bazy dla wielu wyrażeń SQL. Dobrą praktyką jest podział aplikacji na możliwie małe części i wyodrębnienie kodu, który może być wielokrotnie używany. Dla utworzenia naprawdę skalowalnej aplikacji kod ten może być przeniesiony do COM i zarejestrowany w MTS. Po prawidłowej rejestracji MTS określa które obiekty COM są niezbędne w transakcji i śledzi udane i nieudane wykonania każdego obiektu. Access 2000 (i wszystkie poprzednie wersje) nie potrafi w pełni wykorzystać możliwości Microsoft Transaction Server. Mimo to możesz tworzyć aplikacje z wykorzystaniem MTS, aby uzyskać szybkość działania, skalowalność i łączenie połączeń, musisz użyć bardziej zaawansowanej bazy danych, takiej jak Microsoft SQL Server, aby w pełni skorzystać z wszystkich poziomów wsparcia transakcyjności. Oprócz zarządzania transakcjami MTS zarządza tworzeniem i usuwaniem obiektów. Pozwala to na tworzenie obiektów COM wtedy, gdy są potrzebne, zwiększając szybkość wykonywania aplikacji i zapobiegając zwiększaniu obciążenia serwera. MTS zarządza także łączeniem połączeń do bazy. Pozwala to użytkownikom na współdzielenie połączeń zamiast indywidualnego połączenia dla każdego użytkownika. Bez łączenia połączeń 500 użytkowników wymaga 500 połączeń do bazy danych. MTS pozwala na około 10-krotne zmniejszenie ilości połączeń. Jeżeli połączenie jest nieużywane, jest ono pożyczane do wykorzystania przez innego użytkownika, a następnie oddawane do wspólnej puli dostępnych połączeń. Ilość połączeń jest zwiększana, gdy wszystkie dostępne połączenia są zajęte. Jest to wspaniałe usprawnienie i daje niesamowity wzrost wydajności aplikacji. Na rynku znajduje się wiele dobrych książek, które szczegółowo opisują działanie, konfigurację i uwagi dotyczące programowania dla Microsoft Transaction Server. Szczegółowe opisywanie tych tematów wykracza poza ramy tej książki. Jeżeli masz zamiar tworzyć aplikacje oparte o transakcje lub aplikacje wymagające wbudowanej skalowalności, powinieneś na pewno poznać MTS. Teraz, gdy już wiesz co zainstalować, jak zainstalować i jakie podstawowe funkcje są dostępne, omówimy konfigurację usług WWW. Zarządzanie i konfiguracja serwera WWW Do konfiguracji serwisów WWW, w zależności od tego czy pracujesz na Windows 95/98, czy Windows NT (Server lub Workstation), używa się dwóch różnych narzędzi. Powinieneś zapoznać się z interfejsem użytkownika narzędzia właściwego dla Twojej platformy. Personal Web Manager Program pracujący na Windows 95/98 nazwany został Personal Web Manager i posiada bardzo prosty interfejs użytkownika umożliwiający konfigurację serwera WWW. Dostępne jest pięć głównych opcji: Main, Publish, Web site, Tour oraz Advanced. Wybór opcji z paska nawigacyjnego z lewej strony okna lub z menu View otwiera odpowiedni obszar w głównej części okna. ? Ekran Main (rysunek 24.1) jest miejscem, w którym można uruchamiać i zatrzymywać lokalną usługę WWW. Na tym ekranie wyświetlone są również podstawowe informacje na temat serwisu. Oprócz uruchamiania i zatrzymywania serwisu można odczytać położenie głównej strony WWW (katalog domowy), adres WWW strony głównej (ponad przyciskiem start / stop) i niektóre statystyki ruchu na Twoim serwerze (grupa Monitoring). Rysunek 24.1. Strona Main programu Personal Web Manager jest zwykle używana do uruchamiania i zatrzymywania usługi WWW Możesz uruchomić lub zatrzymać usługę WWW, klikając prawym klawiszem myszki ikonę PWS w zasobniku systemowym (dolny prawy róg ekranu obok zegara) i wybierając żądaną opcję z menu. ? Kolejna strona jest interfejsem do kreatora publikacji. Zgodnie z dokumentacją Microsoftu, kreator ten automatycznie skopiuje pliki do katalogu sieciowego i doda połączenie do tego katalogu z Twojej strony domowej. Jednak kreator nie zawsze działa najlepiej i zwykle lepiej samemu zmodyfikować odpowiednie pliki. ? Po wybraniu Web Site można utworzyć domyślną stronę domową lub zmienić istniejącą. Jest to bardzo proste narzędzie i można się bez niego obejść, szczególnie, gdy jesteś prawdziwym programistą WWW. ? Tour dostarcza podstawowych informacji, prawdopodobnie nic ponad to, co już wiesz. Jeżeli jesteś ciekawy, przejrzyj dostępne ekrany informacyjne. ? Większość funkcji potrzebnych do programowania WWW zawarta jest w części Advanced, która pokazana jest na rysunku 24.2. Za pomocą tej opcji można tworzyć katalogi wirtualne, ustawiać domyślne dokumenty i zarządzać właściwościami katalogów. Termin „katalog wirtualny” nie jest właściwie rozumiany przez niektórych programistów. Jest on dokładnie wyjaśniony w części „Różnica pomiędzy witryną a katalogiem wirtualnym” tego rozdziału. Katalogi wirtualne zostaną później szczegółowo objaśnione, ale powinieneś zapamiętać, że posiadają one trzy poziomy dostępu ustawiane podczas tworzenia katalogu: Read, Execute i Script (rysunek 24.3). Zawsze zaznaczaj poziom dostępu Read, jeżeli tego nie zrobisz, nikt nie będzie mógł oglądać Twojej witryny. Jeżeli masz zamiar oglądać strony ASP bez tworzenia katalogu wirtualnego, powinieneś zaznaczyć pole wyboru umożliwiające wykonywanie skryptów (ASP są skryptami VBScript wykonywanymi na serwerze). Rysunek 24.2. Będziesz używał strony Advanced programu Personal Web Manager do tworzenia i zarządzania katalogami wirtualnymi Rysunek 24.3. Prawa dostępu dla nowego katalogu wirtualnego w Personal Web Manager Jeżeli zaznaczysz opcję Execute dla katalogu wirtualnego, wszystkie pliki wykonywalne w nim umieszczone będą mogły być wykonywane, włączając w to interpretery skryptów (jak np. Perl) i pliki binarne Windows (pliki EXE i DLL). Program konfiguracji usług WWW w systemie Windows NT / Windows 2000 jest nazywany Microsoft Management Console i jest nieco bardziej wymagający. Jeżeli programujesz na Windows 95/98 i masz osobę, która administruje serwerem produkcyjnym na Windows NT, możesz opuścić ten fragment rozdziału. Microsoft Management Console Program Microsoft Management Console (MMC), pokazany na rysunku 24.4, jest głównym narzędziem do zarządzania wszystkimi usługami, które są częścią Option Pack na Windows NT, oraz będzie dużą i ważną częścią Windows 2000 (następcy Windows NT). Dobrym pomysłem jest zapoznanie się z nim, jeżeli planujesz używać kolejnych wersji Microsoft Windows NT. Po otwarciu MMC można zauważyć, że lewy panel posiada dwie rozwijalne opcje. Prawy panel jest oknem szczegółów i będzie zawierał informacje specyficzne dla opcji wybranych po lewej stronie. Pierwszą pozycją w liście w lewym panelu jest Console Root, właściwie jest to sam MMC. Każda pozycja poniżej nazywana jest wtyczką i pozwala na wykonywanie specyficznych operacji zwykle ograniczonych do jednej usługi. Windows 2000 będzie posiadało wiele dostępnych wtyczek dla MMC. Rysunek 24.4. Microsoft Management Console (MMC) jest głównym narzędziem do administracji usługami sieciowymi Konfiguracja Internet Information Server Pierwsza wtyczka (jedyna, którą opiszemy w tej książce) służy do zarządzania programem Internet Information Server. Jeżeli rozwiniesz jeden poziom tej gałęzi, zobaczysz tam nawę NetBios Twojego komputera. Rozwinięcie jeszcze jednego poziomu odkryje różne opcję zależne od zainstalowanych usług. Zwykle znajdują się tam: ? Default FTP Site; ? Default Web Site; ? Administration Web Site; ? Default SMTP Site. Opisanie każdej z tych opcji wykracza poza ramy tej książki, ale zajmiemy się kilkoma opcjami dotyczącymi konfiguracji serwera WWW (gałąź Administration Web Site), ponieważ wpłyną one na pracę i wydajność Twoich aplikacji WWW. Wykonamy teraz kilka zmian w konfiguracji serwera. Na początek wybierze nazwę lokalnego serwera i kliknij ją prawym klawiszem myszki. Tak jak w przypadku wielu aplikacji Windows wyświetlone zostało menu z najczęściej używanymi opcjami (rysunek 24.5). Wybierzemy Properties z menu. Spowoduje to wyświetlenie domyślnych opcji całego serwera. Można dostać się do tych opcji przez wybranie właściwości poszczególnych witryn, ale wtedy trzeba wykonywać zmiany dla każdej witryny osobno. Zmienimy teraz położenie plików śladu. Option Pack ustawia ich położenie w c:\winnt\ system32\logfiles\.Na pierwszy rzut oka nie wzbudza podejrzeń, ale przecież pliki śladu mogą urosnąć do sporych rozmiarów na uczęszczanym serwerze. Może to spowodować zatkanie dysku systemowego, czego należy unikać. Rysunek 24.5. Kliknięcie prawym klawiszem na opcję wyświetla menu podręczne z listą możliwych do wykonania funkcji Na dole zakładki Web Site wybierz Logging Properties. Następnie przejdź na zakładkę General i zmień położenie plików śladu serwera WWW. Może być to katalog, który już istnieje w systemie. Może być to d:\logfiles\, jest poza partycją systemową i jest łatwy do odszukania. Jeżeli wybierzesz zakładkę Extended Properties, możesz wybrać, które informacje będą zapisywane do plików śladu, gdy klient zażąda strony. Nie wybieraj wszystkiego. Każda rzecz, którą zapisujesz, powoduje dodatkową aktywność dysków i obciążenie systemu. Dla najlepszej wydajności wybierz tylko te informacje, których naprawdę potrzebujesz. Kliknij kilka razy przycisk OK, aby wrócić do głównego okna właściwości WWW. Teraz zajmiemy się zakładką Documents. Możesz podać na niej jeden lub więcej domyślnych dokumentów (rysunek 24.6). IIS używa tej informacji do wybrania pliku, który będzie załadowany jako pierwszy. Jeżeli ktoś wpisze www.NazwaWitryny.com bez podawania nazwy pliku, IIS rozpoczynając od góry listy szuka pliku o podanej nazwie, dopóki go nie znajdzie lub nie dojdzie do końca listy. Jeżeli plik nie istnieje na serwerze lub nie ma co najmniej jednego wpisu do listy domyślnych dokumentów, użytkownik dostanie komunikat błędu. Ponieważ moja firma, ORCS Web, Inc utrzymuje wiele serwisów klientów, zawsze dodajemy plik index.html do każdego serwera WWW, taki jest standard przyjęty w systemie UNIX i wielu użytkowników jest do tego przyzwyczajonych. Rysunek 24.6. Czasami będziesz chciał zmienić nazwę domyślnego dokumentu lub dodać więcej domyślnych dokumentów do listy dla konkretnej witryny Przejdźmy znów do okna właściwości WWW i omówimy teraz zakładkę Directory Security. MMC pozwala na zarządzanie dodatkowymi ustawieniami zabezpieczeń, które działają razem z Windows NT File System (rysunek 24.7). Znajdują się tu trzy grupy opcji, które udostępnia IIS. Rysunek 24.7. Bezpieczeństwo jest prawie zawsze problemem każdego systemu przyłączonego do Internetu ? Anonymus Access and Authentication Control (Dostęp anonimowy i zarządzanie uwierzytelnianiem); ? Secure Comunications (Bezpieczny przesył danych); ? IP Address and Domain Name Restrictions (Ograniczenie adresów IP i nazw domen). Wybierz Anonymus Access and Authentication Control. Masz do wyboru trzy opcje: ? Allow Anonymous Access (zezwolenie na dostęp anonimowy); ? Basic Authentication (podstawowe uwierzytelnianie, hasło przesyłane jest otwartym tekstem); ? Windows NT Challenge/Response (uwierzytelnianie próba/odpowiedź). Jeżeli chcesz umożliwić anonimowy dostęp do Twoich stron, zaznacz pierwsze pole wyboru (Allow Anonymous Access). Opcja ta powoduje, że IIS najpierw sprawdza, czy użytkownik IUSER (omówiony później w części „Co to jest IUSER ?”) posiada prawo do dostępu do pliku lub strony. Jeżeli tak, przyjmuje, że klientem jest IUSER i przetwarza żądanie. Jeżeli opcja ta nie jest aktywna lub użytkownik IUSER nie posiada prawa do żądanego pliku, proces autoryzacji jest ponawiany dla pozostałych dwóch opcji. Jeżeli włączona jest autoryzacja próba/odpowiedź i klientem jest Internet Explorer, nazwa użytkownika i hasło użyte do zalogowania do klienta zostaną przesłane do serwera WWW i następuje próba autoryzacji. Przy użyciu tego sposobu autoryzacji hasło jest przesyłane do serwera w bezpiecznej zaszyfrowanej postaci. Jeżeli użytkownik i hasło pasują do konta na serwerze (lokalnego lub pochodzącego z domeny), użytkownik otrzymuje żądaną stronę lub nie, w zależności od jego uprawnień. Jeżeli nie zostanie dopa- sowane żadne konto użytkownika, żądanie dostępu zostanie odrzucone. Jeżeli klient nie używa przeglądarki Internet Explorer, podczas uwierzytelniania hasło przesyłane będzie otwartym tekstem. Aby autoryzować użytkowników, którzy nie używają przeglądarki Internet Explorer, IIS umożliwia uwierzytelnianie przy użyciu nieszyfrowanego hasła. Metoda ta nie jest bezpieczna, ale jest wystarczająca, jeżeli musisz zabezpieczyć jakiś fragment swojego serwera, a nie jesteś pewien, jakiej przeglądarki używają klienci. Uaktywnienie obu opcji jest zwykle najlepszym wyborem. Na początku IIS spróbuje autoryzować się jako IUSER (jeżeli jest aktywny), a następnie spróbuje autoryzacji Windows NT. Jeżeli nadal nie uzyska dostępu, spróbuje podstawowej autoryzacji. Wybranie Secure Communication w oknie właściwości serwera WWW, gdy nie mamy jeszcze zainstalowanego klucza bezpieczeństwa, powoduje otwarcie narzędzia Key Manager. Jeżeli zdecydujesz się na użycie Secure Socket Layer (SSL), musisz od tego zacząć. W oknie tym można wygenerować żądanie wygenerowania klucza, które jest wysyłane do centrum autoryzacji, np.: VeriSign. Po przetworzeniu żądania należy wprowadzić otrzymany certyfikat do Key Managera aby zakończyć proces instalacji klucza. Po zainstalowaniu klucza SSL przycisk zmienia się z Key Manager na Edit. Wybranie Edit pozwala na włączenie trybu dostępu SSL do ochrony przesyłanych stron. URL umożliwiający dostęp do stron powinien być podawany wtedy w postaci https:// zamiast http://. Elektroniczny handel staje się coraz bardziej popularny. Aby bezpiecznie przesyłać przez Internet poufne dane (jak numery kart kredytowych), musisz użyć SSL. Masz również możliwość ograniczenia dostępu do witryny, opierając się o adresy IP klientów. Nie jest to zbytnio użyteczne, chyba że serwer jest używany w Intranecie. Większość adresów IP klientów w Internecie zmienia się, ponieważ są one dynamicznie przydzielane przez ich ISP. Jeżeli decydujesz się na ograniczenie dostępu oparte o adres IP, możesz podać listę klientów, którzy nie mają dostępu do witryny, lub przeciwnie, podać listę klientów mających dostęp do witryny. Powróćmy do okna właściwości serwera WWW na zakładkę Home Directory (rysunek 24.8). Tutaj wprowadzasz ustawienia dotyczące Twojej aplikacji. Pole tekstowe Local Path zawiera ścieżkę do katalogu zawierającego witrynę, której właściwości właśnie oglądamy. Pola wyboru Access Permissions pozwalają zdecydować, czy serwer pozwala na odczyt, zapis, obie operacje lub odmawia dostępu. Nie spotkałem się jeszcze z sytuacją, gdzie byłby potrzebny zapis, więc można zaznaczyć tylko pole Read. Za pomocą pól Content Control można ustawiać cztery opcje: Rysunek 24.8. Zakładka Home Directory pozwala na zarządzanie najniższą warstwą ustawień witryny WWW, takich jak katalog na serwerze ? Log Access. Jeżeli pole to jest zaznaczone, włączasz zapisywanie informacji do plików śladu ustawionych na zakładce Web Site. Wszystkie zgłoszenia HTTP będą powodowały pojawienie się wpisów w plikach śladu serwera WWW. ? Directory Browsing Allowed. Jeżeli zaznaczymy tę opcję i nie będzie domyślnej strony domowej w przeglądarce zostanie wyświetlona lista plików i katalogów. ? Index This Directory. Mówi usłudze Index Server, że należy śledzić i indeksować pliki zawarte, w tej witrynie dla potrzeb przeszukiwania serwera. ? Front Page Web. Oznacza, że ta witryna jest witryną FrontPage lub Visual InterDev i obsługuje rozszerzenia FrontPage Extensions. W dolnej części tej zakładki znajdują się ustawienia aplikacji. Aplikacja w rozumieniu Microsoftu to niezależny zbiór stron Active Server Pages, które współdziałają ze sobą w celu wykonania jakiejś operacji (to jest moja definicja, nie Microsoftu). Przed zmianami w tej części okna upewnij się, że uaktywnione jest prawo do wykonywania skryptów. Umożliwia ono wykonywanie stron ASP na serwerze i wysyłanie wyników działania do przeglądarki. Widziałem u niektórych ludzi włączone prawo do wykonywania programów (ponieważ było tak w IIS3), ale jest to absolutnie nieprawidłowe. Dopuszczenie wykonywania programów jest niezbędne tylko dla katalogów zawierających CGI lub Perl, ale w innych przypadkach nie powinno się włączać tego prawa. Umieszczenie pliku wykonywalnego w katalogu, w którym możliwe jest uruchamianie, pozwala na uruchomienie tego programu na serwerze i spowodowanie nieprzewidzianych efektów. Kliknij przycisk Configuration, aby uruchomić okno zawierające szczegóły wpływające na wydajność i możliwości stron ASP. Okno konfiguracji posiada trzy zakładki: App Mappings, App Options oraz App Debugging. Na zakładce App mapings wymienia się wszystkie typy plików (rozszerzenia) i aplikacje, które są używane do przetwarzania tych plików. Musisz co najmniej pozostwić typy .asa i .asp uruchamiane przez ASP.DLL. Na liście znajduje się kilka innych typów plików, ale jeżeli jesteś pewien, że ich nie używasz, możesz usunąć je z listy, poprawiając nieco wydajność serwera. Na zakładce App Options można ustawić opcję pozwalającą na ustalanie sesji przez aplikację i określenie czasu, przez jaki będzie ta sesja utrzymywana (rysunek 24.9). Bądź ostrożny przy modyfikacji tych ustawień, ponieważ mają one drastyczny wpływ na działanie i wydajność serwera WWW. Większość programistów korzysta z korzyści ustanawiania sesji, jest to jedna z najlepszych funkcji w ASP. Jeżeli jednak możesz uniknąć stosowania sesji, odczujesz ogromne przyśpieszenie działania aplikacji. Rysunek 24.9. Ustawienia aplikacji stają się ważne dla pracy serwera, gdy coraz lepiej poznajesz technologię WWW firmy Microsoft Na zakładce tej można również włączyć buforowanie (przyspiesza to działanie aplikacji), uaktywnić ścieżki względne (pozwala to ASP na rozwijanie ścieżek względnych korzystając z katalogu rodzica) oraz podanie domyślnego języka skryptów (zwykle jest to VBScript, ale może być JScript). Można również podać wartość limitu czasu dla skryptów. Zwiększanie tej wartości pozwoli na wykonywanie dłuższych skryptów bez komunikatu błędu, ale niepotrzebnie blokuje zasoby serwera. Lepiej pozostawić domyślne 60 sekund i podawać dłuższe limity czasu w stronach ASP w razie potrzeby (<% Server.ScriptTimeout=180 %>). Ostatnia zakładka, App Debugging, zawiera opcje pozwalające ustalić czy umożliwić debugowanie skryptu na serwerze, kliencie, po obu stronach lub wyłączyć tę możliwość. Można również wprowadzić własny komunikat błędu wysyłany do klienta, gdy strona ASP spowoduje błąd. Jest to dobra funkcja, ponieważ lepiej u klienta nie wyświetlać systemowego komunikatu błędu. Jednak podczas uruchamiania aplikacji wyłącz tę funkcję, ponieważ nie będziesz wiedział, co poszło źle. Zabezpieczanie aplikacji WWW Jednym z problemów, z którymi stykają się użytkownicy po zainstalowaniu IIS lub PWS, jest bezpieczeństwo. Jest ono szczególnie ważne, gdy pisze się aplikację obsługującą handel elektroniczny lub inną zawierającą ważne dane. Istnieje kilka podstawowych czynności, które powinny być wykonane. Niektóre z nich opisane są później w „ASP/HTML – położenie i uprawnienia” oraz „Bazy danych – położenie i uprawnienia”. Wymienione tam ustawienia zabezpieczeń są wymagane dla zapewnienia podstawowego bezpieczeństwa wymaganego dla aplikacji WWW, jednak podane są dodatkowe czynności, które mogą być podjęte, aby chronić ważne dane i zabezpieczać przed dostępem do witryny przez niepożądanych ludzi. Wiele firm uruchamia ściany ognia (ang. firewall) pomiędzy ich serwerami a Internetem. Takie zabezpieczenie pozwala na uruchomienie szczegółowych zabezpieczeń na to, kto może dostać się do serwera oraz w jaki sposób. Bardzo często ściany ognia blokują dostęp z zewnątrz do serwerów dla wszystkich portów poza portem 80 (port HTTP). Pozwala to na przepuszczenie wywołań HTTP do serwera i uruchomienie aplikacji WWW, jednak nie pozwala na dostęp do innych nieautoryzowanych portów. Opcje, które do tej pory omawialiśmy, i wprowadzone zmiany dotyczą całego serwera. Oprócz zmieniania ustawień dla całego serwera można ustawić niektóre opcje konfiguracji dla katalogu wirtualnego. Różnice pomiędzy witryną a katalogiem wirtualnym Witryna jest oddzielną jednostką na serwerze WWW identyfikowaną przez unikatową nazwę domeny. Internet Information Server na Windows NT Server dobrze obsługuje wiele witryn na pojedynczym serwerze. Tylko sprzęt ogranicza ilość witryn, które możesz uruchomić na pojedynczym serwerze. Katalog wirtualny zawsze zawiera się w witrynie i jest przypisany tylko i wyłącznie do tej witryny. Katalog wirtualny może mieć własne ustawienia dla WWW, które mogą być różne od ustawień dla reszty witryny, co umożliwia łatwe zarządzanie zawartością witryny. Przykładowo, jeżeli chcesz uruchamiać CGI w witrynie (nie jest to zalecane ze względów wydajności, ale możliwe), powinieneś umieścić wszystkie pliki CGI w jednym katalogu wirtualnym i nadać mu prawo wykonywania programów. Microsoft FrontPage i Visual InterDev w różny sposób traktują konfiguracje katalogów wirtualnych. Jeżeli używasz któregoś z tych narzędzi, najlepiej pozwolić na stworzenie katalogu wirtualnego przez narzędzie. Po utworzeniu katalogu przez program nie zmieniaj jego ustawień. Wielu programistów „zepsuło” swoje witryny przez zmianę ustawień WWW lub uprawnień plików na witrynach tworzonych przez FrontPage lub Visual InterDev. Prawdopodobnie jedną z najlepszych funkcji katalogu wirtualnego jest to, że może być umieszczony gdziekolwiek na serwerze. Może być również umieszczony na dysku sieciowym mapowanym z innego serwera (wymaga to specjalnych ustawień konfiguracji, które wykraczają poza ramy tej książki). Więc jeżeli witryna ma adres www.witryna.com, a katalog wirtualny o nazwie „użytkownik1” umieszczony jest w d:\użytkownik1, będzie on dostępny jako http://www.witryna.com/uzytkownik1/ nawet, gdy katalog ten jest fizycznie odizolowany od obszaru serwera. Mimo że katalog wirtualny może znajdować się w dowolnym miejscu, powinien być umieszczony w drzewie katalogów WWW. Struktura katalogów dla aplikacji WWW powinna zostać wcześniej przemyślana. Posiadanie wielu katalogów wirtualnych rozsianych w różnych miejscach serwera powoduje duże problemy w utrzymaniu. Jednym z najbardziej użytecznych zastosowań katalogów wirtualnych jest kontrola dostępu do zawartości WWW. Załóżmy, że mamy serwis WWW położony w d:\wwwroot\. Masz również dwóch współpracowników, którzy chcą mieć własne fragmenty serwera, którymi będą zarządzać sami. Niezależnie od tego, czy będą mieli dostęp do swoich katalogów poprzez dysk sieciowy, czy FTP, trudno jest zabezpieczyć się przed możliwością uzyskania przez nich dostępu do głównego obszaru serwera, jeżeli tylko utworzysz katalogi d:\wwwroot\user1\ i d:\wwwroot\user2\. Jednym ze sposobów poprawienia bezpieczeństwa i ograniczenia dostępu użytkowników tylko do ich plików, jest utworzenie katalogów d:\wwwroot\user1\ i d:\wwwroot\user2\ i przypisanie katalogów wirtualnych do tych obszarów. Kolejną świetną funkcją katalogów wirtualnych jest funkcja dostępna tylko na Windows NT, możliwość podania punktu startowego dla aplikacji. Pozwala to na odizolowanie zmiennych sesji i aplikacji oraz całkowite odizolowanie od innych aplikacji WWW nawet, gdy znajdują się na jednym serwerze. Mimo że możesz tworzyć aplikacje WWW na Windows 95/98, nie ma sposobu na tworzenie wielu aplikacji i korzystanie z ich izolacji, tak jak można to zrobić na Windows NT. Na serwerze WWW pracującym w Windows 95/98 wszystkie strony udostępniane przez PWS traktowane są jako jedna aplikacja WWW. Zmienne sesji tworzone w katalogu wirtualnym na Windows 95/98 są dostępna dla wszystkich katalogów wirtualnych tej witryny. Jeżeli chcesz uruchamiać wiele aplikacji WWW na jednym serwerze, jest to jeszcze jeden powód, aby użyć Windows NT. Wywołując okno właściwości katalogu wirtualnego na Windows NT, można ustawić opcje w inny sposób niż dla reszty witryny. Wszystkie opcje wymienione we wcześniejszej części rozdziału dostępne są również dla katalogu wirtualnego. Powoduje to większą elastyczność i zarządzanie pojedynczymi aplikacjami WWW i pozwala na ustawianie specyficznych opcji, które mogą być niezbędne w jednej aplikacji a niepotrzebne w innej. Na zakładce Home Directory mamy możliwość utworzenia aplikacji w katalogu wirtualnym, którego właściwości właśnie oglądamy. Po wskazaniu tego katalogu jako aplikacji będzie ona pracować niezależnie od reszty witryny. Znaczy to, że ta aplikacja posiada własny plik global.asa oraz oddzielną konfigurację. Wszystkie sesje oraz zmienne globalne aplikacji dostępne są tylko i wyłącznie w tej aplikacji. Próba dostępu do tych zmiennych spoza bieżącej aplikacji, nawet z tego samego serwera, nie powiedzie się. Umożliwia to izolację i podwyższony poziom bezpieczeństwa. Globalny plik global.asa powinien być umieszczony w katalogu będącym punktem startowym aplikacji. Jeżeli zadeklarowałeś katalog wirtualny jako aplikację, plik global.asa powinien znajdować się w fizycznym katalogu, który zdefiniowałeś jako katalog startowy katalogu wirtualnego. Jeżeli potrzebujesz jeszcze większej izolacji, możesz zażądać, aby aplikacja pracowała w oddzielnej przestrzeni pamięci. Uaktywnienie tej funkcji wymaga od serwera WWW przełączania kontekstu i może mieć negatywny wpływ na wydajność systemu. Korzyścią tego rozwiązania jest to, że aplikacja żądająca takiego traktowania jest izolowana i jej awaria nie wpłynie na inne aplikacje pracujące na tym samym serwerze. Czy teraz, gdy mamy zainstalowany serwer WWW i wiemy jak go skonfigurować, jest już wszystko gotowe? Nie do końca. Jest jeszcze kilka punktów, o których musisz wiedzieć i brać pod uwagę podczas tworzenia i udostępniania aplikacji WWW. Mimo że ustawiłeś podstawowe opcje w trakcie przygotowywania aplikacji, musisz zwrócić uwagę na środowisko poza ustawieniami WWW. Jednym z ważniejszych zagadnień jest bezpieczeństwo oraz właściwe ustawienie aplikacji, aby miała dostęp do odpowiednich plików i źródeł danych. Co to jest IUSER ? W trakcie instalacji IIS/PWS na Windows NT tworzone jest nowe konto użytkownika o nazwie IUSER_, gdzie jest nazwą NetBios nadana serwerowi (w oknie właściwości sieci). Gdy ktoś chce obejrzeć stronę WWW, a na serwerze IIS uaktywniony jest anonimowy dostęp, IIS na początku sprawdza prawo NTFS do odczytu pliku przez użytkownika IUSER. Jeżeli IUSER posiada wystarczające prawa do oglądania tej strony, jest ona wysyłana do przeglądarki. Jeżeli IUSER nie ma odpowiednich praw do tego pliku lub IIS nie pozwala na anonimowy dostęp, IIS spróbuje autoryzować użytkownika zgodnie z ustawieniami w MMC. Typ systemu plików Mimo że IIS posiada kilka zaszytych w sobie opcji zapewniających niewielki poziom bezpieczeństwa witryny, jest on niewystarczający dla większości wypadków bez wsparcia ze strony zabezpieczeń Windows NT. Gorąco polecamy użycie Windows NT File Sysem (NTFS) na partycji zawierającej pliki witryny WWW oraz bazę danych. Pozwala to na uaktywnienie zabezpieczeń na poziomie dostępu do plików i katalogów, co jest jedyną drogą zabezpieczenia serwera produkcyjnego. NTFS jest dostępny tylko na Windows NT. Jeżeli tworzysz aplikację na Windows 95/98, nie będziesz mógł utworzyć tak szczelnego systemu bezpieczeństwa, jaki można utworzyć na Windows NT. Jest to jeszcze jeden powód umieszczenia gotowej aplikacji na Windows NT. Struktura katalogów i wymagane uprawnienia Standardowa konfiguracja komputera na serwer WWW posiada dwie partycje, jedna mała (około 1 GB) na system operacyjny i druga na wszystkie związane z WWW pliki oraz pliki śladu. Rodzaj systemu plików użytego dla partycji systemowej jest zależny od upodobań, ale prawie zawsze partycja zawierająca witrynę WWW posiada system plików NTFS w celu zapewnienia odpowiedniego poziomu bezpieczeństwa. W trakcie instalacji IIS wprowadza się ścieżkę do głównego katalogu WWW. Zakładając, że znajduje się ona na drugiej partycji, domyślną ścieżką jest d:\inetpub\wwwroot\. Jest to obszar, do którego IIS będzie kierował wszystkie żądania WWW, chyba że konfiguracja została zmodyfikowana. Gdy spojrzysz na właściwości tego katalogu przy użyciu MMC, zauważysz, że wszystkie przydziały adresów IP są ustawione na „nieprzydzielone”, więc nawet, gdy posiadasz wiele adresów IP na serwerze, wszystkie żądania kierowane będą do tego katalogu. Upraszczając, przyjmiemy, że na serwerze znajduje się jedna witryna umieszczona w katalogu d:\inetpub\wwwroot. ASP/HTML – położenie i uprawnienia Zakładamy, że posiadasz ogólną wiedzę na temat uprawnień w NT i szybko prześledzimy wymagania dla IIS. Aby obejrzeć dokument HTML, użytkownik IUSER musi mieć co najmniej prawo czytania pliku. Do obejrzenia dokumentu Active Server Pages, użytkownik musi posiadać, co najmniej prawo uruchamiania tego pliku. Jeżeli przypisałeś użytkownikowi prawo czytania tego pliku (rysunek 24.10), odpowiednim prawem NT, które należy przydzielić, jest prawo Read & Execute (RX). Gdy mówimy o prawach Read & Execute, mamy na myśli najniższy poziom uprawnień NT, które znajdują się w oknie specjalnych uprawnień pliku lub katalogu (rysunek 24.11). Mimo że pozwala to na dostęp zarówno do stron HTML oraz ASP, nie jest to niezbędne ani najbardziej bezpieczne rozwiązanie, jeżeli bezpieczeństwo jest priorytetem. Rysunek 24.10. NTFS na Windows NT posiada niektóre domyślne ustawienia praw, które w większości przypadków spełniają wymagania bezpieczeństwa Rysunek 24.11. Jeżeli potrzebujesz lepszej kontroli uprawnień do pliku, możesz zejść do specyficznych uprawnień używając specjalnych uprawnień do pliku Bazy danych – położenie i uprawnienia Jeżeli używasz Active Server Pages, aby podłączyć się do bazy danych Accessa, baza danych nie musi znajdować się w głównym katalogu witryny WWW. Ponieważ ścieżka jest podana w ciągu połączenia, możesz umieścić ją w dowolnym miejscu. Ze względów bezpieczeństwa zaleca się umieścić bazę danych w katalogu, który jest odizolowany od plików WWW. D:\databases\ jest świetnym rozwiązaniem. Uniemożliwia to złośliwym klientom wpisanie http://www.witryna.com/baza/bazadanych.mdb i zapisanie pliku bazy danych na swoim komputerze. Zabezpieczenie bazy danych może wydawać się pełne sztuczek, gdy nie zna się kilku szczegółów. Istnieją dwa sposoby zabezpieczenia bazy danych, poprzez wbudowany w Access system zabezpieczeń lub poprzez ustawienie praw NTFS do pliku. Jeżeli posiadasz aplikację, która tylko odczytuje informacje i nigdy nie wprowadza informacji do bazy, sprawa jest prosta. Nadaj użytkownikowi IUSER tylko prawo do czytania pliku bazy danych. Jeżeli teraz nie robisz nic poza czytaniem z bazy, prawdopodobnie nie potrwa to długo. Jedną z największych korzyści aplikacji WWW jest dynamiczne wyświetlanie informacji użytkownikom, jednak to tylko połowa sukcesu. Możliwość dopisywania danych do bazy przyniesie wiele korzyści. Można zapisywać zwrotne informacje od użytkowników, informacje z listy dyskusyjnej, bieżące zamówienia i inne dane. Pozwala to użytkownikom na lepszą interakcję z witryną i pomaga na lepsze obsłużenie klientów. Załóżmy, że mamy bazę danych do zbierania zamówień przez sieć. Po ustawieniu uprawnień do zapisu i odczytu próba zapisu do bazy kończy się niepowodzeniem. Gdy baza jest używana przez użytkownika, który ma prawo do zapisu, tworzy on plik blokad. Ponieważ użytkownik IUSER posiada takie prawo, Access próbuje utworzyć plik i powoduje błąd niedozwolonego dostępu. Aby nie występował ten błąd, użytkownik IUSER musi posiadać prawo do zmiany zawartości w katalogu, w którym znajduje się baza danych. Prawo do zmian jest niezbędne, ponieważ plik blokad musi być uaktualniany przy każdym wykonaniu polecenia SQL. Prawa do tworzenia i czytania nie wystarczą. Jeżeli nie przeniosłeś bazy danych do osobnego katalogu, zaczyna to wyglądać źle. Jeżeli masz bazę danych w drzewie katalogów witryny WWW, użytkownik IUSER musi posiadać prawa do czytania, zapisu i usuwania w katalogu bazy danych, co jest BARDZO ZŁYM rozwiązaniem. We wczesnych etapach naszych eksperymentów z bazami danych, aplikacjami WWW i wymaganiami bezpieczeństwa, jeden z autorów i ja zrobiliśmy tak, jak to opisałem wcześniej. Nie czekaliśmy zbyt długo na hakera, który zauważył, że witryna jest dla niego szeroko otwarta i dokonał zmian w naszych plikach. Jeżeli używasz serwera SQL, system bezpieczeństwa jest zapewniany przez serwer bazy, co pozwala na uniknięcie potencjalnych problemów przy zarządzaniu zabezpieczeniami na poziomie plików. Rozdział 25. Przenoszenie Accessa 2000 do sieci WWW za pomocą komponentów sieciowych Office W tym rozdziale: ? Czym są komponenty sieciowe Office. ? Użycie formantu Office Arkusz. ? Użycie formantu Office Wykres. ? Użycie formantu Office Tabela przestawna. Jak już wiesz, w obecnych czasach nie ignoruje się Internetu. Microsoft poszukiwał dla Office 2000 prostej metody przeniesienia możliwie wiele z podstawowych możliwości Office 2000 do Internetu. Rezultatem prac są komponenty sieciowe Office 2000 oraz strony dostępu do danych (opisane w rozdziale 26., „Użycie stron dostępu do danych”). W tym rozdziale przedstawione zostanie wprowadzenie do komponentów sieciowych Office. Czym są komponenty sieciowe Office Komponenty sieciowe Office są zbiorem formantów ActiveX opartych na technologii COM, dostarczających niektóre podstawowe funkcje arkusza, wykresu i tabeli przestawnej, zawarte w Office, dla przeglądarki internetowej obsługującej technologię ActiveX. W Office 2000 komponenty sieciowe składają się z: ? Formantu Office Arkusz; ? Formantu Office Wykres; ? Formantu Office Tabela przestawna. Te trzy formanty graficzne (Spreadsheet, Chart oraz PivotTable) oraz formant DataSource są oparte o COM, więc mogą być używane przez VBScript, JScript, VB, C++, Java oraz oczywiście VBA. To, że są one nazwane komponentami sieciowymi, nie oznacza, że są dostępne tylko na stronach WWW. Mogą również spełniać ważną rolę w aplikacjach Accessa. Rysunek 25.1 przedstawia prosty arkusz kalkulacyjny umieszczony na formularzu Accessa. Rysunek 25.1. Komponent sieciowy Office umieszczony na formularzu Accessa Co potrafią komponenty sieciowe Office Każdy komponent posiada inne funkcje, które można użyć w aplikacji. Formant Arkusz to mini Excel do wbudowania w stronę WWW lub formularz. Posiada on większość podstawowych funkcji Excela, jak przeliczanie, filtrowanie czy sortowanie. Możesz użyć formantu Arkusz jako niewidocznej maszyny liczącej w aplikacji Accessa, VB lub WWW. Wykres umożliwia tworzenie dwuwymiarowych wykresów i posiada możliwość łączenia z innymi elementami HTML jak formant Arkusz lub źródło danych. Wykres pozwala również na eksport rysunków GIF dla przeglądarek WWW, które nie obsługują formantów ActiveX. Formant Tabela przestawna udostępnia funkcję tworzenia tabel przestawnych dostępną w Excelu, poprzez formant ActiveX. Tabela przestawna tak jak Wykres potrafi również eksportować pliki GIF. Dostępny jest również formant DataSource, który nie posiada postaci graficznej. DataSource działa analogicznie do formantu Data w Visual Basicu. Łączy się on z bazą danych i pozwala innym formantom na dołączenie się do niego. Każdy z wymienionych formantów zostanie bliżej omówiony w następnym rozdziale. Wymagane licencje na użycie komponentów sieciowych W przeciwieństwie do formantów ActiveX, komponenty sieciowe wymagają zakupienia licencji Office 2000 dla każdego komputera klienta. Użytkownicy nie muszą mieć zainstalowanego pakietu Office 2000, jednak muszą mieć na niego licencję. Jeżeli pracujesz w dużej firmie i chcesz użyć komponentów sieciowych oraz stron ADP (opisane w następnym rozdziale), możesz skorzystać z licencji typu site i rozprowadzać komponenty sieciowe jeszcze przed zainstalowaniem Office 2000. Użycie formantu Office Arkusz Użycie formantu Arkusz jest podobne do użycia Excela. Można go stosować na dwa sposoby, w formie związanej i niezwiązanej. Forma związana wymusza użycie formantu DataControl, który omówimy w następnym rozdziale. Tutaj zajmiemy się użyciem formantu w postaci niezwiązanej. Rozpoczynamy Excel 2000 posiada funkcję radykalnie ułatwiającą użycie formantu Arkusz, jest to automatyczne przenoszenie arkusza Excela do postaci strony WWW. W Excelu 2000 utwórz prosty arkusz. Następnie wybierz z głównego menu Plik, Zapisz jako stronę sieci Web. Na ekranie pojawi się okno dialogowe pokazane na rysunku 25.2. Okno to pozwala na wybór zakresu lub eksport całego arkusza. Jeżeli chcesz zapisać dane do interaktywnej strony WWW, musisz zdefiniować swoje dane jako zakres w Excelu. Aby wyeksportować wybrany zakres do formantu Arkusz na stronie WWW, zaznacz pole wyboru Dodaj interakcję (rysunek 25.2). Rysunek 25.2. Okno Zapisz jako stronę sieci Web Po zapisaniu arkusza jako strony WWW przez Excela możesz otworzyć wynikową stronę w przeglądarce Internet Explorer (rysunek 25.3). Po otwarciu strony WWW możesz kliknąć prawym klawiszem myszy formant i otworzyć Przybornik właściwości (rysunek 25.4). Okno to utworzone w Dynamic HTML pozwala na formatowanie i zarządzanie układem formantu Więcej informacji na temat użycia tego formantu w sieci WWW znajduje się w następnym rozdziale. Rysunek 25.3. Wynika zapisu arkusza Excela 2000 jako strony WWW Rysunek 25.4. Okno przybornika właściwości arkusza Użycie formantu w Accessie Aby wstawić formant Arkusz na formularz Accessa, z głównego menu wybierz Wstaw, Formant ActiveX. Otworzy się okno dialogowe Wstawianie formantu ActiveX (rysunek 25.5). Przewiń listę dostępnych formantów do Arkusz pakietu Microsoft Office 9.0 i kliknij OK. Spowoduje to wstawienie formantu do formularza w trybie projektowania (rysunek 25.6). Po wstawieniu formantu na formularz należy napisać procedurę pobierającą dane do arkusza w trakcie ładowania formularza. Wydruk 26.1 zawiera procedurę obsługi zdarzenia Load formatki. Procedura otwiera recordset ADO oparty o kwerendę „Dziesięć najdroższych produktów” w bazie danych Northwind. Następnie przegląda wynik. Dla każdego wiersza użyta jest domyślna właściwość ActiveCell w celu wstawienia danych z wyniku kwerendy do komórek arkusza. W trakcie przesuwania się w wyniku należy zwiększać właściwość ActiveCell, aby wstawić dane do kolejnych wierszy arkusza. Jak widać, jest to podobne do programowania w Excelu. Po wstawieniu zmień nazwę formantu na Spreadsheet1 w oknie właściwości. Rysunek 25.5. Okno dialogowe Wstawianie formantu ActiveX Rysunek 25.6. Formant Arkusz na formularzu Accessa w trybie edycji Wydruk 25.1. Ładowanie danych do formantu Arkusz w trakcie pracy programu Private Sub Form_Load() 'Ładuje do formantu ActiveX Arkusz 'dane pochodzące z kwerendy z Accessa Dim rst As ADODB.Recordset Dim intCount As Integer On Error GoTo Proc_Err Set rst = New ADODB.Recordset rst.Open "[Ten Most Expensive Products]", CurrentProject.Connection ' Wpisywanie nagłówków Spreadsheetl.ActiveCell(1, 1) = "Produkt" Spreadsheetl.ActiveCell(1, 2) = "Cena" ' Inicjuj licznik pętli intCount = 2 Do Until rst.EOF ' Wypełnij bieżącą komórkę zawartością rekordu Spreadsheetl.ActiveCell(intCount, 1) = "" & _ rst!TenMostExpensiveProducts Spreadsheetl.ActiveCell(intCount, 2) = "" & _ rst!UnitPrice ' Przejdź do kolejnego rekordu i zwiększ wartość licznika rst.MoveNext intCount = intCount + 1 Loop rst.Close Set rst = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Użycie formantu Office Wykres Mogłeś pomyśleć, że straciłeś zbyt dużo czasu, zajmując się programem Microsoft Graph. Formant Wykres jest prosty do użycia i bardzo potężny. Jak inne formanty, może być użyty w trybie związanym i niezwiązanym. Teraz zajmiemy się użyciem formantu w trybie niezwiązanym, natomiast tryb związany zostanie omówiony w następnym rozdziale. Dodatkowo w rozdziale 27. „Publikowanie w sieci przy użyciu Accessa 2000 i Active Server Pages” przedstawimy, jak używać tego komponentu do eksportowania rysunków GIF używanych w ASP. Rozpoczynamy Tak jak w przypadku formantu Arkusz rozpoczniemy od utworzenia prostego wykresu w Microsoft Excel 2000, pokazanego na rysunku 25.7. Wybierz Plik, Zapisz jako stronę sieci Web, a następnie wybierz Zaznaczenie: Wykres oraz zaznacz pole wyboru Dodaj interakcję. Wynik jest pokazany na rysunku 25.8. Można manipulować takim wykresem za pomocą skryptów uruchamianych na komputerze klienta np.VBScript lub JScript. Aby używać formantu w skryptach, musisz znać właściwości i metody, jakie udostępnia formant. Omówimy je w dalszej części rozdziału. Rysunek 25.7. Wykres w Microsoft Excel 2000 Rysunek 25.8. Formant Wykres wyeksportowany jako strona WWW Użycie formantu w Accessie Wstaw formant na formularz Accessa przy użyciu Wstaw, Formant ActiveX. Musisz wybrać z listy formantów ActiveX „Wykres pakietu Microsoft Office 9.0”. Po utworzeniu formantu zmień jego nazwę na Chart1 w oknie właściwości. Gdy używasz formantu Wykres w trybie niezwiązanym musisz pamiętać o dwóch ważnych sprawach. Po pierwsze, formant Wykres może przechowywać wiele obiektów, więc każdy utworzony wykres będzie częścią kolekcji Charts. Po drugie, możesz wypełnić tablice wartości dla serii wykresów i tablicę wartości dla danych serii wykresów. Aby to przedstawić, stworzyłem prostą kwerendę przestawną w demonstracyjnej bazie danych Northwind, za pomocą następującego wyrażenia SQL: TRANSFORM Sum(CCur([Order Details].[UnitPrice]* [Quantity]*(1-[Discount])/100)*100) AS ProductAmount SELECT Year([OrderDate]) AS OrderYear FROM Products INNER JOIN (Orders INNER JOIN [Order Details] ON Orders.OrderID = [Order Details] ON Products.ProductID = [Order Details].ProductID WHERE (((Orders.OrderDate) Between #1/1/1997# And #12/31/1997#)) GROUP BY Year([OrderDate]) PIVOT "Qtr " & DatePart("q",[OrderDate],1,0) In ("Qtr 1","Qtr 2","Qtr 3","Qtr 4"); Podane wyrażenie SQL dzieli całkowitą sprzedaż na kwartały i wylicza wynik pokazany na rysunku 25.9. Rysunek 25.9. Prosta kwerenda przestawna w Accessie 2000 Teraz skorzystamy z utworzonej kwerendy przestawnej, aby utworzyć niezwiązany wykres w procedurze obsługi zdarzenia Open formularza. Utworzona została tablica aHeaders, wypełniona nazwami nagłówków dla serii (w tym przypadku czterema kwartałami roku podatkowego). Następnie otwierany jest recordset ADO oparty o zapisaną kwerendę przestawną nazwaną qryQuarterlySales i wypełniana jest tablica aValues wartościami pól z wyniku kwerendy. Cały tekst procedury przedstawiony jest na wydruku 25.2. Wydruk 25.2. Tworzenie niezwiązanego wykresu Private Sub Form Open(Cancel As Integer) 'Ładuje do formantu ActiveX Wykres 'dane pochodzące z kwerendy z Accessa Dim ChartSpace1, aHeaders(3), aValues(3) Dim rst As ADODB.Recordset On Error GoTo Proc_Err Set rst = New ADODB.Recordset ' Tworzenie tablicy elementów dla wykresu aHeaders(0) = "Q1" aHeaders(1) = "Q2" aHeaders(2) = "Q3" aHeaders(3) = "Qq" ' Otwarcie recordsetu opartego o kwerendę XTAB ' i wypełniamy wartości dla słupków wykresu rst.Open "qry0uarterlySales", CurrentProject.Connection aValues(0) = rst![Otr 1] aValues(1) = rst![Qtr 2] aValues(2) = rst![Otr 3] aValues(3) = rst![Otr 4] Set ChartSpace1 = Me.Chart1 With ChartSpace1 .Border.Color = chColorAutomatic ' Można mieć więcej niż jeden wykres w ' obszarze wykresu, więc należy odwołać się do kolekcji .Charts.Add With .Charts(0) .Type = chChartTypeColumnClustered .SeriesCollection.Add .SeriesCollection(0).Caption = "Sprzedaż w 1999" ' Wiązanie danych do wcześniej stworzonych tablic .SeriesCollection(0).SetData _ chDimCategories, chDataLiteral, aHeaders .SeriesCollection(0).SetData _ chDimValues, chDataLiteral, aValues .HasLegend = True End With End With rst.Close Set rst = Nothing Proc_Exit: Exit Sub Proc_Err: MsgBox Err.Description Resume Proc_Exit End Sub Użycie formantu Office Tabela przestawna Tak jak w przypadku dwóch formantów przedstawionych w tym rozdziale, Tabela przestawna może być używana w trybie związanym i niezwiązanym. Dalsza część rozdziału przedstawi sposób użycia formantu w trybie niezwiązanym, natomiast w następnym rozdziale przedstawimy sposób wiązania formantu do danych na stronie dostępu do danych. Rozpoczynamy Tabele przestawne są jedną z najpopularniejszych funkcji programu Microsoft Excel. Dają one możliwość tworzenia od ręki raportów w Excelu. Wielu użytkowników staje się entuzjastami tabel przestawnych po nauczeniu ich tworzenia. Możliwość tworzenia tabel przestawnych i użycia ich jako część witryny WWW lub formularza Accessa jest świetną możliwością. Zacznij od stworzenia tabeli przestawnej w Excelu 2000 w sposób pokazany na rysunku 25.10. Rysunek 25.10. Prosta tabela przestawna w Excelu 2000 Po utworzeniu tabeli przestawnej wybierz Plik, Zapisz jako stronę sieci Web, jednak zamiast kliknąć Zapisz w oknie dialogowym kliknij Opublikuj. Uruchomiony zostanie zaawansowane okno dialogowe Publikowanie jako strony sieci Web (rysunek 25.11). Okno pokazane na rysunku 25.11 pozwala na wybranie do wyeksportowania elementów tabeli przestawnej i ustawienie opcji widoku. Ustawiając opcje widoku, można wybrać opcję tabeli przestawnej. Excel utworzy stronę WWW pokazaną na rysunku 25.12. Rysunek 25.11. Okno dialogowe Publikowanie jako strony sieci Web Rysunek 25.12. Tabela przestawna Excela wyeksportowana do przeglądarki Internet Explorer Rozdział 26. Użycie stron dostępu do danych W tym rozdziale: ? Tworzenie pierwszej strony dostępu do danych ? Tworzenie interaktywnych odnośników ? Łączenie komponentów sieciowych Office z DAP ? Skrypty w stronach dostępu do danych Jak chyba zauważyłeś, obecnie nie ignoruje się Internetu. Tworząc Office 2000 przedstawiciele Microsoftu, poszukiwał prostej metody przeniesienia maksymalnie dużo możliwości Office do Internetu. Wynikiem tych prac są strony dostępu do danych (DAP – Data Access Pages) oraz komponenty sieciowe Microsoft Office 2000. Rozdział ten przedstawia możliwości stron dostępu do danych na podstawie przykładowych stron DAP. Prawdopodobnie zapoznałeś się już z Internetem lub firmowym Intranetem oraz utworzyłeś kilka prostych stron dla użytkowników Twoich programów. Coraz częściej użytkownicy pytają Cię o możliwość oglądania wykresów, diagramów, odnośników oraz utworzenia bardziej interaktywnych, dynamicznych stron WWW. Odpowiadasz, że jesteś specjalistą od baz danych, a nie od programowania dla WWW oraz, że szybkie zrealizowanie tych pomysłów jest bardzo trudne. Projektanci z Microsoftu uświadomili sobie, że użytkownicy chcą więcej możliwości w tworzeniu raportów w sieci i stworzyli w Accessie 2000 mechanizm zwany stronami dostępu do danych. Czym są strony dostępu do danych? Prawdopodobnie zauważyłeś nową pozycję w oknie bazy danych nazwaną Strony. Jest to miejsce na nowe obiekty bazy danych zwane stronami dostępu do danych (DAP). Rysunek 26.1 przedstawia okno bazy danych otwarte na pozycji Strony. DAP to podzbiór raportów i formularzy Accessa zaprojektowanych do pracy w sieci, a dokładniej w Intranecie. Strony te są zapisane jako Dynamic HTML i mogą być oglądane w Internet Explorer 5.0 lub późniejszych. Strona taka podłącza się do pracującej bazy danych i daje możliwość wprowadzania do bazy danych z formularza lub tworzenia raportu z bazy danych. Rysunek 26.1. Nowa sekcja w oknie bazy danych zawierająca strony dostępu do danych Architektura oraz wymagania stron dostępu do danych Strony dostępu do danych używają formantów ActiveX, dynamicznego HTML, ADO oraz skryptów wykonywanych po stronie klienta. Używając skryptów wykonywanych po stronie klienta, musisz mieć zainstalowane na stacjach roboczych ADO i dostawcę OLEDB dla Accessa i serwera SQL. Formaty ActiveX są obsługiwane tylko przez Internet Explorer 4.0 oraz 5.0, więc jesteś ograniczony tylko do przeglądarek Microsoftu. Dodatkowo Microsoft wymaga licencji na Office 2000 do używania stron dostępu do danych. Jedyną gwarancją poprawnej instalacji formantów sieciowych, ADO 2.1 oraz właściwych sterowników i dostawców OLEDB jest instalacja Office 2000. Tworzenie Twojej pierwszej strony dostępu do danych Rozpocznijmy tworzenie naszej pierwszej strony dostępu do danych. Przełącz okno bazy danych na Strony i wybierz Nowy. Następnie wybierz Widok projektu. Na ekranie pojawi się pusta strona w widoku projektu (rysunek 26.2). Zatytułuj stronę poprzez kliknięcie w górnej części strony i wpisanie „Kategorie”. Wywołaj listę pól, wybierając z menu Widok, Lista pól. Lista pól pokazana jest na rysunku 26.3. Zawiera ona wszystkie tabele i kwerendy w bieżącej bazie danych. Lista ta działa jak lista pól w typowym formularzu lub raporcie. Po wyświetleniu listy pól przejdź do tabeli Categories i przeciągnij pola CategoryName oraz Description na stronę. Rysunek 26.2. Pusta strona dostępu do danych w widoku projektu Rysunek 26.3. Lista pól na stronie dostępu do danych Teraz, po dodaniu pól do strony, kliknij przycisk Zapisz z paska narzędzi, lub wybierz z menu Plik – Zapisz. Zauważ, że jest wyświetlone okno dialogowe Zapisz jako stronę dostępu do danych (rysunek 26.4). Strony dostępu do danych nie są zapisywane w pliku MDB jak inne obiekty bazy danych takie jak: tabele, kwerendy, formularze, raporty, makra i moduły. Aby szybko sprawdzić położenie DAP, umieść kursor myszy nad nazwą DAP i poczekaj chwilę (rysunek 26.5). Musisz pamiętać, że DAP nie są przechowywane w pliku MDB. Sprawia to wiele kłopotów podczas rozprowadzania aplikacji. Musisz rozprowadzać plik MDB wraz z wszystkimi utworzonymi stronami dostępu. Oprócz tego musisz utrzymywać zgodność między ADP na dysku i informacją zapisaną w bazie. Możesz jednak zmienić to ograniczenie w korzyść, jeżeli umieścisz DAP na serwerze WWW. Dopóki użytkownicy mają dostęp do serwera WWW poprzez Internet lub Intranet, możesz umieścić pliki DAP na serwerze WWW. Rysunek 26.4. Zapisz jako stronę dostępu do danych Rysunek 26.5. Podpowiedź pokazująca ścieżkę do strony dostępu do danych Zanim skupimy się na stronach dostępu do danych, przyjrzyjmy się funkcji Sortowanie i Grupowanie. Wybierz Widok, Sortowanie i grupowanie z głównego menu. Wyświetlone zostanie okno dialogowe Sortowanie i grupowanie (rysunek 26.6). Rysunek 26.6. Okno dialogowe Sortowanie i grupowanie w stronach dostępu do danych Większość z właściwości jest identyczna jak te używane w raportach, jednak są dwie, na które powinieneś zwrócić uwagę. Pierwszą właściwością jest rozmiar strony danych. Określa ona ilość rekordów wyświetlanych na jednej stronie. Ustawimy ten parametr na 1. Możesz eksperymentować tym parametrem, aby wyświetlić więcej rekordów. Drugą właściwością, z którą powinieneś się zapoznać, jest: Sekcja nawigacji między rekordami. Ustawienie tej właściwości na Tak doda do strony taką właśnie sekcję. Po ustawieniu tych właściwości możemy zająć się formatowaniem strony. Aby formatować stronę dostępu do danych, wybierz z menu Format, Motyw, co spowoduje wyświetlenie okna dialogowego Motyw (rysunek 26.7). Rysunek 26.7. Okno dialogowe Motyw Oglądanie strony dostępu do danych Gotową stronę można oglądać na dwa sposoby: jako część aplikacji Accessa lub w przeglądarce WWW. Aby oglądać stronę w Accessie, kliknij ikonę Widok strony lub wybierz z menu Widok, Widok strony, będąc w trybie projektowania. Jeżeli chcesz wyświetlić stronę w aplikacji Accessa, użyj metody OpenDataAccessPage obiektu DoCmd: DoCmd.OpenDataAccessPage "Kategorie", acDataAccessPageBrowse Rysunek 26.8 przedstawia pokazuje stronę dostępu do danych w Accessie. Należy zauważyć, że można używać strony dostępu do danych w aplikacji identycznie jak formularza czy raportu. Można również oglądać stronę DAP w odpowiedniej przeglądarce WWW. Należy po prostu otworzyć odpowiedni plik HTML z dysku lub serwera WWW. Rysunek 26.9 przedstawia stronę DAP otwartą w przeglądarce WWW. Rysunek 26.8. Strona dostępu do danych wyświetlona w Accessie Rysunek 26.9. Strona dostępu do danych wyświetlona w Internet Explorerze Zauważmy, że strony DAP wyglądają tak samo w przeglądarce jak i w Accessie. Nie tracimy żadnych możliwości. przenosząc stronę z Accessa na stronę WWW. Oglądając stronę w przeglądarce, spróbujmy zmienić dane i przesunąć się do kolejnego rekordu. Można zauważyć, że dane pobierane są z bazy danych, a zmiany zostały do niej wprowadzone. Jeżeli utworzysz swoją aplikację w oparciu o strony dostępu do danych zamiast w oparciu o formularze i raporty, możesz ją łatwo przenieść do sieci WWW. Tworzenie interaktywnych odnośników Potężną opcją w stronach dostępu do danych jest możliwość tworzenia odnośników opartych o relacje jeden – do – wielu zdefiniowane w bazie danych. Utworzymy teraz odnośnik, oparty o relację jeden do wielu z Categories do Products, na naszej stronie Kategorie. Otwórz stronę i wyświetl w przedstawiony wcześniej sposób listę pól dostępnych w bazie danych. Przenieś pola z tabeli Products: ProductName, UnitPrice oraz Discontinued na dół strony. Access utworzy nową sekcję, która będzie sekcją odnośnika (rysunek 26.10). Rysunek 26.10. Podrzędna sekcja odnośnika dla tabeli Products w trybie projektowania Mimo że Microsoft wymaga przestrzegania standardów Windows w aplikacjach, które chcą używać logo Windows, jednak sam ich nie dotrzymuje. Strony dostępu do danych nie posiadają funkcji Cofnij. W trybie projektowania pojawił się przycisk ze znakiem +. Wyświetla on dane odnoszące się do bieżącego rekordu. Można umieścić go w dogodnym miejscu, np. na dole sekcji. Wróćmy jeszcze raz do okna Grupowanie i sortowanie. Ustaw dla sekcji Categories rozmiar strony danych na 1, a dla sekcji Products na Wszystko, oraz Sekcja nawigacji między rekordami dla Products na Nie. W wyniku dostaniemy stronę, która przedstawia wszystkie produkty danej kategorii (rysunek 26.11). Rysunek 26.11. Sekcja odnośnika dla produktów na stronie dostępu do danych Łączenie komponentów sieciowych Office z DAP Potężną opcją w stronach dostępu do danych jest możliwość umieszczania na nich komponentów sieciowych Office, które są połączone dynamicznie z danymi. Rysunek 26.12 przedstawia stronę dostępu do danych utworzoną z użyciem komponentów sieciowych Office. Rysunek 26.12. Strona dostępu do danych ze związanymi komponentami sieciowymi Office Utwórzmy na początek prostą kwerendę krzyżową w przykładowej bazie danych Accessa NorthWind. Utworzymy kwerendę krzyżową z wszystkimi kategoriami produktów i ich sprzedażą kwartalną w roku 1997. Zapis tej kwerendy w SQL wygląda następująco: TRANSFORM Sum(CCur([Order Details].[UnitPrice]*[Quantity]* (1-[Discount])/100)*100) AS ProductAmount SELECT Categories.CategoryName FROM (Categories INNER JOIN Products ON Categories.CategoryID = Products.CategoryID) INNER JOIN (Orders INNER JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID) ON Products.ProductID = [Order Details].ProductID WHERE (((Orders.OrderDate) Between #1/1/1997# And #12/31/1997#)) GROUP BY Categories.CategoryName PIVOT "Qtr " & DatePart("q",[OrderDate],1,0) In ("Qtr 1","Qtr 2","Qtr 3","Qtr 4"); Zapisz tę kwerendę jako QuaterlyProducts i utwórz stronę dostępu do danych bazującą na tej kwerendzie. Dodanie komponentu sieciowego Arkusz Excel Aby dodać komponent Excel do strony dostępu do danych, kliknij ikonę podobną do ikony Excela na pasku narzędzi (rysunek 26.13) i umieść komponent na stronie. Po umieszczeniu komponentu w odpowiednim miejscu należy związać komórki arkusza z polami na stronie tak, aby arkusz zmieniał się, gdy użytkownik będzie przechodził między rekordami. Musisz użyć modelu obiektowego DHTML, gdzie wszystkie obiekty są udostępnione poprzez obiekt document. Aby odwołać się do pola o nazwie txtQ1, wprowadź do komórki: =document.txtQ1.value Dodaj komórkę dla każdego kwartału, sąsiednią komórkę zwiąż z formatem przechowującym daną. Tabela 26.1. Wartości komórek w arkuszu Q1 =document.txtQ1.value Q2 =document.txtQ2.value Q3 =document.txtQ3.value Q4 =document.txtQ4.value Dodanie komponentu sieciowego Wykres Po dodaniu do strony komponentu Arkusz Excel, dodajmy komponent Wykres wiążąc go z danymi w arkuszu. Gdy będziemy przechodzić pomiędzy rekordami, będzie się zmieniać zawartość arkusza oraz uaktualniany będzie wykres. Rysunek 26.13. Pasek narzędzi strony dostępu do danych Komponent Wykres dodajemy do strony poprzez kliknięcie ikony Wykres i narysowanie komponentu na stronie. Po tej operacji zostanie uruchomiony kreator wykresów. Na pierwszej stronie kreatora wybieramy typ tworzonego wykresu. Dostępne typy wykresów są podobne do wykresów 2D Excela. Po wybraniu typu wykresu należy wybrać przycisk Następny. Na drugiej stronie kreatora (rysunek 26.14) wybieramy źródło danych dla wykresu, może być nim tabela lub kwerenda albo arkusz kalkulacyjny istniejący na stronie. Wybierz arkusz kalkulacyjny i kliknij Następny. Na ostatniej stronie ustalamy zakres na arkuszu zawierający wartości i etykiety. Wprowadzamy =A1:A4 jako etykiety oraz =B1:B4 jako wartości. Rysunek 6.14. Kreator wykresu na stronie dostępu do danych Po zakończeniu pracy kreatora przełączamy się w tryb widoku strony i przeglądamy kolejne rekordy. Wykres powinien się zmieniać po przejściu pomiędzy rekordami. Skrypty w stronach dostępu do danych Pisanie procedur kontrolujących strony dostępu do danych nie jest tak proste jak pisanie procedur dla formularzy i raportów. Gdy chcesz napisać program zawarty w stronie DAP, musisz użyć skryptów, aby móc kontrolować zachowanie się strony. Gdy tworzysz przycisk lub inny obiekt udostępniający zdarzenia, musisz napisać VBScript (lub JavaScript). W Accessie nie ma edytora skryptów dla stron dostępu do danych, należy użyć Microsoft Script Editor (MSE), który pokazany jest na rysunku 26.15. Rysunek 26.15. Microsoft Script Editor (MSE) Zamiast panelu nawigacji dostarczanego przez Accessa utworzymy nasz własny. Utwórz cztery przyciski i zatytułuj je: Poprzedni, Następny, Pierwszy, Ostatni. Kliknij prawym przyciskiem myszy stronę i wybierz Microsoft Script Editor z menu kontekstowego. Po uruchomieniu MSE w oknie Script Outline przedstawione są wszystkie obiekty i zdarzenia dostępne na stronie. Wybierz w oknie Script Outline przyciski umieszczone na stronie i kliknij dwukrotnie zdarzenie onClick. W oknie z kodem HTML powinien pokazać się fragment kodu HTML: Istnieje kilka metod, aby napisać kod dla obiektu, jednak wyrażenie For wskazujące na używany obiekt jest domyślnym sposobem. Wewnątrz bloku skryptu wprowadźmy poniższe wyrażenie: MSODSC.CurrentSection.DataPage.MoveFirst Każda strona dostępu zawiera obiekt DataSource o nazwie MSODSC, który z kolei zawiera obiekt DataPage. Użyjemy metod MoveFirst, MoveLast, MoveNext i MovePrevious w odpowiednich przyciskach. Po oprogramowaniu wszystkich czterech przycisków kod powinien wyglądać podobnie do zamieszczonego na wydruku 26.1. Wydruk 26.1. Tworzenie własnych przycisków nawigacyjnych na stronie dostępu do danych Zmiana źródła danych w trakcie działania strony Dopóki strony dostępu do danych nie będą zapisywane we wnętrzu pliku MDB, dystrybucja ich będzie stanowić problem. Najczęściej spotykanym problemem jest to, że strona odwołuje się do niewłaściwej bazy danych. Gdy umieścisz strony DAP na serwerze WWW lub wyślesz pliki HTML do kogoś innego, strony odwoływać się będą do niewłaściwego pliku MDB lub jakiś użytkownik może mieć pliki w innym miejscu niż inni użytkownicy. W stronach DAP zarządzaniem połączeniami zajmuje się niewidoczny komponent sieciowy DataSource, za pomocą którego można dowolnie programować połączenia. Komponent DataSource posiada właściwość ConnectionString, którą można zmieniać programowo. Aby zmienić źródło danych, należy tylko zmienić właściwość ConnectionString obiektu DataSource w następujący sposób: MSODSC.ConnectionString = strConnect Zakładamy, że komponent DataSource nazywa się MSODSC (taka jest jego domyślna nazwa) i strConnect jest prawidłowym ciągiem połączeniowym OLEDB. Twój program powinien dostarczyć właściwy ciąg połączeniowy. Możesz zapytać użytkownika o ścieżkę do pliku bazy danych za każdym uruchomieniem strony DAP. Aby to zrealizować, użyj InputBox lub innego standardowego okna dialogowego wewnątrz programu klienta. Na wydruku 26.2 pokazany jest sposób realizacji przełączenia źródła danych przy użyciu okna InputBox. Program prosi użytkownika o podanie ścieżki do pliku bazy danych Accessa (rysunek 26.16), tworzy właściwy ciąg połączeniowy i przypisuje go do obiektu DataSource. Możesz połączyć tę technikę z użyciem pliku UDL po stronie klienta, aby wyeliminować konieczność ręcznego wpisywania danych. Rysunek 26.16. Wprowadzanie danych o połączeniu Wydruk 26.2. Ustawianie właściwego ciągu połączeniowego w stronie dostępu do danych Rozdział 27. Publikowanie w sieci przy użyciu Accessa 2000 i Active Server Pages W tym rozdziale: ? Użycie Active Server Pages. ? Architektura Active Server Pages. ? Rozpoczynamy pracę z Active Server Pages. ? Active Server Pages. ? Przykład: Tworzenie strony WWW dostępnej dla członków grupy. ? Publikacja w sieci z Accessa 2000 przy użyciu XML. ? Tworzenie wykresów przy użyciu formantu Wykres. Jeżeli chcesz rozwinąć swoje statyczne strony WWW, publikować dane na bieżąco oraz tworzyć interakcyjne strony WWW, powinieneś zapoznać się z Active Server Pages (ASP). Statyczne strony WWW odchodzą w przeszłość. Aby zadowolić użytkowników, powinieneś dać im dostęp do możliwie aktualnych danych. Używając ASP, można zagwarantować, że witryna WWW dostarcza najnowszych informacji. ASP eliminuje wiele czynności potrzebnych do utrzymania witryny WWW. Przykładowo, jeżeli jesteś administratorem witryny, która zawiera stronę z listą użytkowników, powinieneś oprzeć tę stronę na bazie danych. Dawniej musiałbyś ręcznie zmieniać informacje o użytkownikach za każdym razem, gdy dane się zmieniły. Przy użyciu ASP możesz dać użytkownikom możliwość zmiany tych danych poprzez przeznaczoną do tego stronę WWW. Strona z listą użytkowników zostanie automatycznie uaktualniona, gdy ktoś wczyta ją do przeglądarki, ponieważ dane są przechowywane w bazie danych Accessa 2000. Użycie Active Server Pages Strony Active Server Pages są najnowszą technologią oferowaną przez Microsoft dla dynamicznego udostępniania danych w sieci WWW. ASP jest częścią Internet Information Server 3.0 i późniejszych, jest również dostępna w Personal Web Server. Przy użyciu ASP można tworzyć strony WWW następnej generacji, które nie mają ograniczeń starszych technologii jak Common Gateway Interface (CGI) i Internet Database Connector (IDC). Przy użyciu ASP można łatwo tworzyć interaktywne witryny, które umożliwiają indywidualną obsługę klientów, wprowadzanie zamówień, koszyk zakupów i wiele innych funkcji interaktywnych. Wygląd stron WWW może być dostosowywany przez użytkowników i ustawienia te zostaną odtworzone podczas ich kolejnych wizyt. Za pomocą ASP można tworzyć witryny interaktywne, które przechowują zmienne globalne ustawione przez użytkownika i używane podczas wszystkich jego odwiedzin strony. Tradycyjne systemy klient-serwer mogły przechowywać stan sesji pomiędzy kolejnymi stronami w zmiennych globalnych i klasach. Zarządzanie stanem sesji na stronach WWW nigdy nie było takie łatwe. Przy użyciu ASP jest to bardzo łatwe zadanie. Przed ASP potrzebowałbyś skomplikowanych skryptów CGI do zapamiętania, kto był na stronie i w jaki sposób przemieszczał się pomiędzy stronami. W ASP funkcjonalność ta jest gotowa i nie wymaga pisania żadnego programu. Tak jak jego poprzednik IDC/HTX, strony Active Server Pages są niezależne od przeglądarki oraz bardzo łatwe do tworzenia i zmiany. ASP dostarcza ekstremalnej elastyczności w udostępnianiu danych z Accessa 2000 na witrynie WWW. W tym rozdziale pokażemy, czym są strony ASP i jak je tworzyć. Architektura Active Server Pages Na pewno widziałeś w Internecie adres URL podobny do http://www.microsoft.com/default.asp. Plik z rozszerzeniem ASP zawiera stronę Active Server Page. Strony ASP są dostępne tak jak strony HTML za pomocą protokołu HTTP. Ogromną różnicą pomiędzy ASP i HTML jest sposób traktowania takiej strony przez serwer WWW. Strony ASP zawierają zarówno HTML, jak i instrukcje dla serwera WWW. Instrukcje te są skryptami wykonywanymi na serwerze, które dynamicznie tworzą kod HMTL w zależności od warunków, jakie podałeś lub od zawartości bazy danych. Serwer WWW przetwarza instrukcje zawarte na stronie ASP i przesyła wynikowy kod HTML do przeglądarki użytkownika. Strona ASP zawiera HTML lub HTML i skrypty dla serwera. Podczas przetwarzania pliku ASP serwer wykonuje skrypt na serwerze i wysyła do przeglądarki czysty HTML. Ponieważ skrypt wykonywany jest na serwerze, pliki ASP są niezależne od przeglądarki. Jeżeli strona nie zawiera skryptów, jest po prostu wysyłana do klienta. Możesz dla przykładu zmienić rozszerzenie zwykłego pliku HTML na ASP. Tym sposobem utworzyłeś najprostszą stronę ASP. Gdy zażądasz tej strony, serwer wyśle cały kod HTML z pliku ASP. Jeżeli dodasz skrypt do tego pliku, przykładowo zmieniając kolor tła w zależności od dnia tygodnia, skrypt ten zostanie wykonany na serwerze i otrzymasz tylko HTML z prawidłowym znacznikiem . Domyślnym językiem skryptów stron ASP jest VBScript i na nim skupimy się w drugiej części tego rozdziału. VBScript jest podzbiorem Visual Basica i Visual Basica for Applications. Jeżeli znasz już VB i VBA, powinieneś czuć się jak w domu, programując za pomocą VBScript. Jeżeli znasz JavaScript, również możesz go użyć, ASP pozwala na użycie JavaScript. Jeżeli używasz innego języka skryptów jak Perl, możesz użyć go na stronach ASP pod warunkiem zainstalowania wtyczki obsługującej ten język w serwerze WWW. Wtyczkę taką trzeba uzyskać od producenta języka. Ponieważ skrypty wykonywane są na serwerze, a do przeglądarki jest przesyłany tylko wynikowy HTML, skomplikowany kod i reguły biznesowe zawarte w skryptach są bezpieczne. Jeżeli użytkownik obejrzy kod źródłowy strony, zobaczy tylko kod HTML wysłany do przeglądarki. Kod uruchamianego skryptu nie będzie widoczny w przeglądarce. Active Server Pages kontra CGI Strony Active Server Pages są integralną częścią systemu operacyjnego i nie wymagają kompilacji. Aplikacje CGI są kompilowane na docelowym serwerze WWW i wykonywane jako osobny proces. Dla każdego aktywnego użytkownika witryny uruchamiany jest osobny egzemplarz aplikacji CGI, co nie jest efektywne. Program CGI musi być skompilowany za każdym razem, gdy go zmienimy, natomiast gdy zmienimy plik ASP, zostanie on skompilowany przy następnej próbie dostępu do tego skryptu. Oznacza to, że w trakcie tworzenia aplikacji ASP po zapisaniu strony można ją natychmiast obejrzeć w przeglądarce. W odróżnieniu do CGI, strony ASP wykonywane są w ramach jednego procesu, co powoduje drastyczną poprawę wydajności. Ponieważ ASP jest wykonywane w ramach tego samego procesu, ładowany jest tylko jeden egzemplarz silnika ASP dla wszystkich użytkowników aplikacji. Tworzy on wiele wątków obsługujących skrypty. ASP utrzymuje stan sesji dla wszystkich użytkowników witryny. ASP można łatwo zintegrować z istniejącymi danymi, na przykład z bazą danych Accessa 2000. Podczas, gdy trzeba włożyć nieco wysiłku w dostęp do danych ODBC ze skryptów CGI, dostęp poprzez ODBC jest możliwy w Active Server Pages za pomocą ADO. Dodatkowo ADO używa dostawców OLEDB dla Jet, SQL Server i Oracle w sposób przedstawiony w poprzednich rozdziałach, więc możesz używać również tych baz danych w twoich skryptach. Uruchomienie stron ASP Przed konwersją wszystkich obiektów aplikacji należy się upewnić, czy są zainstalowane i działają strony Active Server Pages, czy źródło ODBC lub dostawca OLEDB jest skonfigurowany dla bazy danych i czy skonfigurowany jest katalog wirtualny z prawami do wykonywania skryptów aplikacji. Wszystkie te zagadnienia zostały opisane w rozdziale 24. „Konfiguracja serwera WWW do publikowania w sieci WWW”. Rozpoczynamy pracę z Active Server Pages Za pomocą Microsoft Access 2000 można wyeksportować każdy obiekt bazy danych jako stronę ASP. Gdy konwertujesz obiekt bazy danych na Active Server Page, ASP będzie wyświetlało tabelę HTML z danymi w tym obiekcie. Użytkownicy nie będą mogli zmieniać i kasować istniejących rekordów ani dopisywać nowych, chyba że dopiszesz odpowiedni fragment programu. Funkcja eksportu jako ASP nie jest funkcją konwersji Accessa na ASP. Aby skonwertować obiekt bazy danych do ASP przy użyciu interfejsu użytkownika Accessa, uruchom kreator, wybierając z głównego menu Plik, Eksportuj. Wybierz typ pliku Active Server Pages. Następnie otwarte zostanie okno pokazane na rysunku 27.1. Rysunek 27.1. Okno eksportu do ASP W oknie pokazanym na rysunku 27.1 należy podać nazwę źródła danych ODBC, hasło bazy danych, URL i limit czasu sesji. Wprowadź dowolną nazwę źródła danych, nazwę użytkownika i hasło, ponieważ będziemy zmieniać wynikowy plik. W polu URL wpisz URL serwera WWW, gdzie będzie umieszczony plik ASP (przykładowo www.mojserwer.com). Limit czasu sesji jest czasem, jaki ASP będzie czekało przed zamknięciem połączenia, jeżeli nie będzie aktywności na stronie. Po upływie tego czasu ASP usunie informacje o stanie sesji i zwolni zajętą pamięć. Domyślnie ASP przyjmuje 20 minut jako limit czasu sesji. Po wykonaniu eksportu w podanym katalogu znajdzie się plik ASP. Możesz zapisać stronę ASP w katalogu, który jest katalogiem wirtualnym z prawem wykonywania skryptów w serwerze WWW. Sposób konfiguracji katalogu opisany jest w rozdziale 24. Po zapisaniu pliku przez Accessa sprawdźmy, co zostało zrobione. Jako domyślnego dostawcę OLEDB do eksportu ASP Access używa ODBC. Aby ominąć to ograniczenie, otwórz wygenerowaną stronę ASP w Notatniku. Treść strony wygenerowanej przez kreatora zamieszczona jest na wydruku 27.1. Wydruk 27.1. Wynik eksportu tabeli Klienci z bazy danych Northwind do ASP Klienci <% If IsObject(Session("Northwind_conn")) Then Set conn = Session("Northwind_conn") Else Set conn = Server.CreateObject("ADODB.Connection") conn.open "Northwind","Admin","" Set Session("Northwind_conn") = conn End If %> <% If IsObject(Session("Klienci_rs")) Then Set rs = Session("Klienci_rs") Else sql = "SELECT * FROM [Klienci]" Set rs = Server.CreateObject("ADODB.Recordset") rs.Open sql, conn, 3, 3 If rs.eof Then rs.AddNew End If Set Session("Klienci_rs") = rs End If %> <% On Error Resume Next rs.MoveFirst do while Not rs.eof %> <% rs.MoveNext loop%>
Klienci
ID klienta Nazwa firmy Przedstawiciel Stanowisko Adres Miasto Region Kod pocztowy Kraj Telefon Faks
<%=Server.HTMLEncode(rs.Fields("IDklienta").Value)%>
<%=Server.HTMLEncode(rs.Fields("NazwaFirmy").Value)%>
<%=Server.HTMLEncode(rs.Fields("Przedstawiciel").Value)%>
<%=Server.HTMLEncode(rs.Fields("StanowiskoPrzedstawiciela").Value?)%>
<%=Server.HTMLEncode(rs.Fields("Adres").Value)%>
<%=Server.HTMLEncode(rs.Fields("Miasto").Value)%>
<%=Server.HTMLEncode(rs.Fields("Region").Value)%>
<%=Server.HTMLEncode(rs.Fields("KodPocztowy").Value)%>
?
<%=Server.HTMLEncode(rs.Fields("Kraj").Value)%>
<%=Server.HTMLEncode(rs.Fields("Telefon").Value)%>
<%=Server.HTMLEncode(rs.Fields("Faks").Value)%>
Chcemy zmienić informację o połączeniu ADO w pliku ASP tak, aby używał on OLEDB. Należy zmienić tylko jeden wiersz kodu zawierający ciąg połączeniowy. Kreator próbuje otworzyć połączenie ADO za pomocą nazwy DSN, którą podaliśmy w oknie kreatora. Ponieważ podaliśmy wymyśloną nazwę DSN, należy zmienić połączenie, aby używało dostawcy OLEDB dla Jet (dla Accessa) i wskazać plik MDB na serwerze. Należy użyć odpowiedniej składni przedstawionej w rozdziale 6. „Wprowadzenie do obiektów danych ActiveX”. Należy zmienić wiersz z postaci: conn.open "Northwind", "Admin", "" na: conn.open "Provider=Microsoft.Jet.OLEDB.4.0;data source="c:\northwind.mdb" Zapisz plik w Notatniku i otwórz go w przeglądarce poprzez URL. Rysunek 27.2 przedstawia końcowy wynik konwersji do Active Server Page. Musisz otworzyć ten plik ASP w przeglądarce, używając prawidłowego adresu URL. Przykładowo, aby otworzyć plik ASP na twoim komputerze przy użyciu protokołu HTTP, należy użyć adresu podobnego do: http://localhost/nazwa_katalogu_wirtualnego/plik.asp. Konstrukcja kodu ASP Jak można zauważyć, kreator eksportu tworzy bardzo prosty kod. Na początku otwierany jest obiekt połączenia ADO i na bazie tego połączenia otwierany jest obiekt ADO recordset. W trakcie przesuwania się po wyniku dane kierowane są do tabeli HTML. Dokładniej zostanie to opisane w dalszej części rozdziału. Rysunek 27.2. Tabela skonwertowana do postaci ASP Ograniczenia eksportu stron ASP Mimo że eksport z Accessa pozwala w łatwy sposób rozpocząć pracę z ASP, nie jest tak elastyczny jak mógłby być ani nie utworzy dla Ciebie całej niestandardowej strony ASP. Eksport nie zapewnia żadnej interaktywności tworzonej strony, nie pozwalając na zmiany rekordów czy ich usuwanie. Ponadto strona ASP wygenerowana przez eksport używa wolniejszego i mniej efektywnego połączenia ODBC do podłączenia się do bazy danych. Przy użyciu tej metody możesz utworzyć niektóre robocze strony ASP, ale jeżeli chcesz tworzyć sprawniejsze strony ASP, które dają dodatkowe możliwości lub używają OLEDB, musisz nauczyć się podstaw ASP. Kolejna część rozdziału zaznajomi Cię z podstawami ASP. Active Server Pages Aby tworzyć aplikacje ASP oparte o bazę danych Access 2000, musisz poznać podstawy ASP. Mimo że na temat ASP można napisać oddzielną książkę, ta część rozdziału przedstawia podstawowe informacje pozwalające rozpocząć pracę. Materiał tu przedstawiony pozwala na zbudowanie całkiem rozbudowanej aplikacji WWW. Omówione zostaną: ? Silnik ASP; ? Skrypty VBScript wykonywane na serwerze; ? Obiekty aplikacji i sesji; ? Obiekty żądań i odpowiedzi; ? Plik global.asa. Silnik ASP Active Server Pages to jeden z interfejsów Internet Server Application Programming Interface (ISAPI), które zostały dodane do Internet Information Server (IIS) 3.0 i późniejszych. Gdy przeglądarka żąda pliku z serwera WWW, filtr ISAPI sprawdza, czy żądanie to dotyczy strony ASP. Jeżeli przeglądarka żąda strony ASP, uruchamiany jest interpreter ASP. Przetwarza on plik ASP i rozpoczynając od początku pliku, wykonuje skrypty. Wynikowy kod HTML wysyłany jest do przeglądarki. Następna część rozdziału zawiera informacje o skryptach wykonywanych na serwerze. Skrypty wykonywane na serwerze Plik ASP zawiera skrypty wykonywane na serwerze oraz kod HTML. Skrypty domyślnie są zapisane w języku VBScript i w tym rozdziale skupimy się na nim. Visual Basic Scripting Edition, znany pod nazwą VBScript, jest rozbudowanym językiem skryptów wykonywanych zarówno na serwerze, jak i na maszynie klienta. VBScript jest podzbiorem Visual Basica. VBScript posiada taką samą składnię i możliwości języka jak VBA. Jeżeli używałeś VBA, nauczysz się VBScript bardzo szybko. VBScript nie posiada kilku ważnych funkcji VBA, jednak dzięki temu jest bezpieczniejszy i mniejszy. Przykładowo usunięto obsługę plików, wywoływanie DLL i automatyzacji OLE. Usunięto również wszystkie typy danych (Long, String itd.), a w zamian wszystkie zmienne są typu Variant. Tabela 27.1 zaczerpnięta z dokumentacji VBScript zawiera wszystkie właściwości VBA, które zostały usunięte z VBScript. Tabela 27.1. Wszystkie funkcje VBA niedostępne w VBScript Kategoria Usunięta funkcja lub słowo kluczowe Obsługa tablic Option Base Deklaracja tablic o dolnej granicy <> 0 Kolekcje Add, Count, Item, Remove Dostęp do kolekcji przy użyciu znaku ! (np.: Kolekcja!element) Kompilacja warunkowa #Const #If ... Then ... #Else Przepływ sterowania DoEvents GoSub ... Return, GoTo On Error GoTo On ... GoSub, On ... GoTo Numery wierszy, etykiety wierszy With ... End With Konwersje CVar, CVDate, Str, Val Typy danych Wszystkie wewnętrzne typy danych oprócz Variant Type ... End Type Data i czas Instrukcja Date, Instrukcja Time Timer Tabela 27.1. Wszystkie funkcje VBA niedostępne w VBScript (ciąg dalszy) Kategoria Usunięta funkcja lub słowo kluczowe DDE LinkExecute, LinkPoke, LinkRequest, LinkSend Uruchamianie Debug, PrintEnd, Stop Deklaracje Declare (dla deklarowania bibliotek DLL) New Optional ParamArray Property Get, Property Let Property Set Static Obsługa błędów Erl Error On Error ... Resume Resume, Resume Next Obsługa plików Tradycyjna obsługa plików Funkcje finansowe Wszystkie funkcje finansowe Manipulacja obiektami TypeOf Obiekty Clipboard Collection Operatory Like Opcje Deftype Option Base Option Compare Option Private Module Ciągi znaków Ciągi o stałej długości LSet, Rset Wyrażenie Mid StrConv Użycie obiektów Dostęp do kolekcji przy użyciu ! VBScript jest celowo niewielki, aby zapewnić bardzo szybką i efektywną kompilację. Innym powodem ograniczenia funkcjonalności jest to, że VBScript może być uruchamiany zarówno na serwerze, jak i na komputerze klienta. Jeżeli skrypt jest uruchamiany w przeglądarce na komputerze klienta, nie można dawać mu dostępu do systemu plików komputera. Pozwoliłoby to złośliwym programistom na utworzenie skryptów formatujących dysk. Tabela 27.2 pochodząca z dokumentacji VBScript zawiera listę dostępnych funkcji. Można nauczyć się języka VBScript poprzez próby i eksperymenty z programem VBA, sprawdzając, czy działa on pod VBScript. Dodatkowo Microsoft udostępnił dokumentację języka VBScript. Jest ona dostępna do załadowania z www.microsoft.com/vbasic i jest bezpłatna. Po załadowaniu i zainstalowaniu dokumentacji na komputerze zostaje zainstalowany pełny opis języka oraz przykładowe pliki (rysunek 27.3). Tabela 27.2. Funkcje dostępne w VBScript Kategoria Słowo kluczowe Obsługa tablic Array, Dim, Private, Public, ReDim IsArray, Erase, LBound, Ubound Przypisanie Set Komentarze Komentarze przy użyciu ' lub Rem Stałe, literały Empty, Nothing, Null, True, False Przepływ sterowania Do...Loop, For...Next, For Each...Next, If...Then...Else, Select Case, While...Wend Konwersje Abs, Asc, AscB, AscW, Chr, ChrB, ChrW, Cbool, Cbyte, Ccur, Cdate, Cdbl, Cint, CLng, CSgn, CStr, DateSerial, DateValue, Hex, Oct, Fix, Int, Sgn, TimeSerial, TimeValue, Dates/Times, Date, Time, DateAdd, DateDiff, DatePart, Day, Month, Weekday, Year, Hour, Minute, Second, Now Deklaracje Const, Dim, Private, Public, ReDim, Function, Sub Formatowanie ciągów FormatCurrency, FormatDateTime, FormatNumber, FormatPercent Obsługa błędów On Err, Err Wejście/wyjście InputBox, LoadPicture, MsgBox Literały Empty, False, Nothing, Null, True Matematyka Atn, Cos, Sin, Tan, Exp, Log, Sgr, Randomize, Rnd Obiekty CreateObject, Dictionary, Err, FileSystemObject, GetObject, TextStream Operatory Dodawanie (+), Odejmowanie (-), Potęga (^), Reszta z dzielenia (Mod), Mnożenie (*), Dzielenie (/), Dzielenie całkowite (\), Negacja (-), Łączenie ciągów (&), Równość (=), Nierówność (<>), Mniejszy (<), Mniejszy lub równy (<=), Większy (>), Większy lub równy (>=), Is, And, Or, Xor, Eqw, Imp Opcje Option Explict Procedury Call, Function, Sub Zaokrąglanie Abs, Int, Fix, Round, Sgn Identyfikacja silnika skryptów ScriptEngine, ScriptEngineBuildVersion, ScriptEngineMajorVersion, ScriptEngineMinorVersion Tabela 27.2. Funkcje dostępne w VBScript (ciąg dalszy) Kategoria Słowo kluczowe Ciągi Asc, AscB, AscW, Chr, ChrB, ChrW, Filter, Instr, InstrB, InstrRev, Join, Len, LenB, Lcase, Ucase, Left, LeftB, Mid, MidB, Right, RightB, Replace, Space, Split, StrComp, String, StrReverse, LTrim, RTrim, Trim Warianty IsArray, IsDate, IsEmpty, IsNull, IsNumeric, IsObiect, Typename, VarType Rysunek 27.3. Dokumentacja do VBScript Użycie VBScript na stronach ASP Przy użyciu VBScript można utworzyć świetnie wyglądające witryny, wykorzystując jego możliwość tworzenia skryptów wykonywanych na komputerze klienta (a właściwie skrypty wykonywane są przez przeglądarkę). W tym rozdziale skupimy się tylko na wykorzystaniu skryptów wykonywanych na serwerze, ponieważ tylko ten rodzaj skryptów wykorzystywany jest przez ASP do generowania wynikowego kodu HTML. Poniżej wymienione zostało kilka funkcji, które realizuje VBScript: ? Tworzenie zmiennych, przypisywanie do nich wartości, wykorzystywanie ich w warunkach logicznych lub umieszczanie ich wartości w wynikowym kodzie HTML. ? Wykonywanie operacji na zmiennych przy użyciu If...Then, Select Case i innych operatorów. ? Tworzenie procedur wykonywanych na serwerze w celu wykonania logowania, kontroli dat i formatowania. ? Dynamiczne tworzenie skryptów VBScript w wynikowym kodzie HTML do wykonania w przeglądarce klienta. Skrypty znajdują się w kodzie HTML pomiędzy znacznikami <%>. Możesz mieszać fragmenty HTML i skryptu. Przykładowo, na wydruku 27.2 znajduje się skrypt ASP, który do zmiennej strName przypisuje nazwisko autora, a następnie zamieszcza ten ciąg na stronie WWW. Wydruk 27.2. Przykład pliku ASP używającego zmiennej Variables <% strName="Stephen Forte" %> Hello <%=strName%> Gdy użytkownik zażąda pliku ASP, którego treść znajduje się na wydruku 27.2, serwer WWW wykona skrypt zawarty pomiędzy ogranicznikami <%> i utworzy stronę WWW, która została pokazana na rysunku 27.3. Kod HTML będący wynikiem działania skryptu przedstawiony jest na wydruku 27.3. Wydruk 27.3 zawiera źródło strony WWW z rysunku 27.4. Wydruk 27.3. Źródło HTML strony WWW z rysunku 27.4 Variables Hello Stephen Forte
Rysunek 27.4. Strona WWW utworzona przez skrypt ASP z wydruku 27.2 Porównaj plik ASP z wydruku 27.2 i plik HTML z wydruku 27.3 wygenerowany przez skrypt ASP. Zauważ, że kod VBScript zawarty pomiędzy znacznikami <%> nie został umieszczony w wynikowym kodzie HTML. Fragment <%=strName%> został zastąpiony w wynikowym kodzie przez wartość zmiennej. Fragmenty pomiędzy znacznikami <%> są interpretowane i wykonywane przez serwer, a wyniki działania tego kodu są wysyłane do przeglądarki jako czysty kod HTML. W kolejnym przykładzie, zamieszczonym na wydruku 27.4, użyta zostanie pętla do zwiększania wartości zmiennej, która jest używana w kodzie HTML. Wydruk 27.4. Skrypt ASP wykonywany na serwerze Creating Hello World with Incremental Text Size Increase <% for i = 3 to 7 %> >Hello World
<% next %>

Gdy użytkownik zażąda pliku ASP zamieszczonego na wydruku 27.4, VBScript pięć razy wykona pętlę, zwiększając za każdym razem wielkość czcionki, co w wyniku da stronę HTML pokazaną na rysunku 27.5. Źródło wynikowej strony zamieszczone jest na wydruku 27.5. Rysunek 27.5. Strona WWW będąca wynikiem wykonania skryptu ASP z wydruku 27.4 Wydruk 27.5. Źródło strony WWW utworzonej przez skrypt ASP z wydruku 27.4 Creating Hello World with Incremental Text Size Increase Hello WOrld
Hello World
Hello World
Hello World
Hello World


Jak zostało to pokazane na tych dwóch przykładach, strony ASP używają skryptów VBScript wykonywanych na serwerze do generacji zwykłego kodu HTML. Aby zwiększyć możliwości stron WWW, należy skorzystać z niektórych wbudowanych obiektów ASP, które teraz omówimy. Obiekty aplikacji i sesji Używając ASP, można skorzystać z kilku wbudowanych obiektów, które są dostępne dla aplikacji. W tej części opiszemy sposób użycia każdego z tych obiektów w aplikacji ASP. Jest to jednak tylko wprowadzenie w temat użycia obiektów w aplikacjach. Dokładnego opisu zagadnienia należy szukać w innych książkach serii „Księga eksperta”. Użycie obiektu aplikacji W czasie tworzenia stron ASP zakłada się, że każdy katalog wirtualny jest odrębną aplikacją. ASP odwołuje się do każdej aplikacji jako obiektu. Obiekt Application używany jest do zarządzania wspólnymi danymi i jest dostępny dla wszystkich użytkowników aplikacji. Obiekt Application tworzony jest z chwilą pierwszego dostępu do stron aplikacji po uruchomieniu serwera WWW. Jest dostępny dla wszystkich użytkowników odwiedzających witrynę tak długo dostępny aż do chwili, gdy we wszystkich sesjach upłynie limit czasu oczekiwania lub zostanie wyłączony serwer WWW. Do obiektu Application można dynamicznie dołączać właściwości, które są traktowane jak zmienne globalne dostępne we wszystkich plikach aplikacji i dla każdego użytkownika aplikacji. Składnia użycia właściwości obiektu Application jest następująca: <%Application("nazwa_właściwości")=wartość %> Przykładowo, możemy sprawdzić, ilu użytkowników jednocześnie używa aplikacji. Możesz przygotować właściwość VisitorNum w następujący sposób: <%Application("VisitorNum")=0 %> Następnie po zalogowaniu się użytkownika do naszego systemu należy zwiększyć wartość zmiennej globalnej o jeden i wyświetlić liczbę aktualnie pracujących użytkowników. Aby liczba ta była zgodna ze stanem faktycznym, po wylogowaniu użytkownika należy zmniejszyć licznik. Aby zwiększyć wartość właściwości, użyj następującego wiersza: <%Application("VisitorNum")= Application("VisitorNum")+1 %> Podczas wylogowywania użytkownika należy użyć: <%Application("VisitorNum")= Application("VisitorNum")-1 %> Aby wyświetlić liczbę jednocześnie zalogowanych użytkowników, użyj następującego wiersza: Jednocześnie pracuje <%Application("VisitorNum")%> użytkowników Podsumowując. Obiekt Application jest używany do przechowywania zmiennych globalnych, których można używać w każdej stronie aplikacji i które są dostępne dla wszystkich użytkowników. Aby użyć indywidualnych zmiennych globalnych dla poszczególnych użytkowników, należy skorzystać z obiektu Session, który jest opisany w kolejnej części rozdziału. Użycie obiektu sesji Prawdopodobnie najważniejszym obiektem, o którym powinieneś się dowiedzieć, jest obiekt Session. ASP utrzymuje automatycznie stan sesji i to właśnie obiekt Session przechowuje stan sesji dla bieżącego użytkownika. Jeżeli jednocześnie strony używa 200 użytkowników, utworzonych jest 200 obiektów Session. Obiekt ten pozwala na tworzenie własnych właściwości dostępnych globalnie dla użytkownika odwiedzającego witrynę. Przykładowo można pozwolić użytkownikowi na podanie imienia i wybór ulubionego koloru. Przy użyciu właściwości obiektu Session można wygenerować stronę WWW w podanym przez użytkownika kolorze i umieścić na niej imię użytkownika. Obiekt sesji tworzony jest przy dostępie użytkownika do witryny WWW i usuwany jest po opuszczeniu witryny lub po upłynięciu czasu nieaktywności sesji. Aby odwołać się do niestandardowych właściwości obiektu Session, należy użyć składni identycznej jak przy odwołaniach do obiektu Application: <%Session("nazwa_właściwości")=wartość %> Po ustawieniu właściwości można odwoływać się do niej z wszystkich stron witryny. Użycie obiektów żądań i odpowiedzi Opisane w poprzedniej części obiekty Application i Session mają możliwość tworzenia niestandardowych właściwości i utrzymują stan sesji. Kolejne dwa obiekty, Response i Redirect, posiadają metody pozwalające, poprzez skrypty wykonywane na serwerze, na wykonywanie określonych akcji i dostęp do danych. Obiekt Response Aby obsłużyć komunikację pomiędzy przeglądarką i serwerem, należy użyć obiektu Response. Obiekt Response posiada on osiem metod dostępnych dla programisty, jednak na potrzeby ASP i Accessa 2000 omówimy tylko metody Redirect i Write. Response.Redirect Gdy chcesz wyświetlić jakąś stronę w przeglądarce, powinieneś w skrypcie ASP użyć metody Redirect obiektu Response. Przykładowo, wyobraźmy sobie stronę WWW, na której znajduje się formularz, w którym użytkownik podaje nazwę użytkownika. Jeżeli użytkownik ten istnieje w bazie danych, użytkownik zostaje przeniesiony na stronę główną, jeżeli nie istnieje, na stronę rejestrowania nowego użytkownika. Można skorzystać z konstrukcji If...Then razem z metodą Response.Redirect w następujący sposób: <%If fLogin=True then 'Użytkownik zautoryzowany Response.Redirect "welcome.html" Else 'Nie ma takiego użytkownika Response.Redirect "newmember.asp" End if%> Response.Write W trakcie tworzenia skryptu ASP, który wypisuje tekst do wynikowego pliku HTML, można użyć metody Write obiektu Response. Response.Write ma bardzo prostą składnię: Response.Write("ciąg tekstu") Przykładowo, można tworzyć różne komunikaty umieszczane na stronie w zależności od zdefiniowanego warunku. Możesz spytać użytkownika o wiek, a następnie utworzyć w zależności od odpowiedzi odpowiednią stronę, używając metody Write. Podany poniżej fragment skryptu demonstruje taką właśnie technikę. <%If intAge < 21 Then Response.Write("Prawo w Nowym Jorku") Response.Write("zabrania sprzedawania alkoholu") Response.Write("młodzieży do lat 21") Else Response.Redirect "buy.asp" End If%> Obiekt Request Aby sprawdzić, co użytkownik wpisał do pola tekstowego na stronie WWW, powinieneś użyć obiektu Request. Obiekt ten potrafi pobrać informację z wielu miejsc w przeglądarce, jednak skupimy się teraz tylko na pobieraniu wartości z formularza zawartego na stronie WWW. Każdy formularz zawarty na stronie HTML składa się z elementów HTML, takich jak pola tekstowe i listy wyboru. Jeżeli nadasz tym elementom nazwy i wywołasz plik ASP, można odczytać wartości z tych elementów za pomocą następującego wywołania: Request.Form("nazwa_elementu") Możesz użyć obiektu Request.Form do odczytania informacji o użytkowniku i wstawić je do bazy danych Accessa 2000, lub utworzyć odpowiednie wyrażenie SQL. Można również przypisać do zmiennej ciąg, który wpisał użytkownik przy użyciu wyrażenia podobnego do następującego: <% intAge=Request.Form("txtWiek")%> Plik global.asa Strony ASP używają specjalnego pliku o nazwie global.asa. Jest on umieszczony w katalogu, który jest korzeniem drzewa katalogu wirtualnego i służy on do zarządzania zdarzeniami obiektów Application i Session. Plik ten jest również używany do tworzenia zmiennych Application i Session. Obiekty Application i Session posiadają zdarzenia, które są wykonywane na początku i na końcu istnienia obiektów. Są to: ? Application_OnStart; ? Application_OnEnd; ? Session_OnStart; ? Session_OnEnd. Można użyć tych zdarzeń do tworzenia zmiennych, wstawiania lub szukania rekordów w bazie danych oraz upewnić się, że użytkownik wlogował się. Plik global.asa nie działa jak domyślny dokument w katalogu wirtualnym. Pierwsze odwołanie do niego następuje, gdy użytkownik po raz pierwszy uruchomił dowolną stronę z katalogu wirtualnego. Plik global.asa nie tworzy kodu HTML jak pliki ASP, zamiast tego wykonywany jest kod obsługi odpowiednich zdarzeń obiektów Application oraz Session. Wraz z rozwojem ASP Microsoft doda kolejne zdarzenia do ASP, które będą obsługiwane przez kod zawarty w pliku global.asa. Kod zamieszczony na wydruku 27.6 jest przykładowym plikiem global.asa ze zdefiniowaną obsługą zdarzeń OnStart dla obiektów Application i Session. Dla obiektu Application ustawiana jest zmienna VisitorNum w celu zliczania ilości jednocześnie wlogowanych użytkowników. W obsłudze zdarzenia OnStart obiektu Session zestawiane jest połączenie do przykładowej bazy danych, aby każda strona mogła używać utworzonego tu obiektu Connection (więcej o połączeniach do bazy znajduje się w rozdziale 6. „Wprowadzenie do obiektów danych ActiveX” i rozdziale 7. „Zaawansowane ADO”). Oprócz połączenia do bazy tworzonych jest pięć zmiennych dostępnych dla całej sesji zainicjowanych informacjami pochodzącymi z bazy danych. Wydruk 27.6. Plik global.asa dla przykładowego katalogu wirtualnego Przykłady użycia obiektów ASP Na koniec przedstawimy przykład, w którym używane są obiekty ASP. Przykładowa strona WWW używa zmiennych będących niestandardowymi właściwościami obiektów Application i Session. W obiekcie Application utworzone zostały zmienne Start oraz VisitorNum. W trakcie obsługi zdarzenia OnStart obiektu Application do zmiennej Start został przypisany bieżący czas. Jest on również przypisywany do zmiennej Start z obiektu Session. Czas zapisany w obiekcie Session może nie być bieżącym czasem, ponieważ zdarzenie OnStart obiektu Session jest wywoływane, gdy użytkownik odwoła się do dowolnej strony z katalogu wirtualnego aplikacji. Wydruk 27.7 zawiera przykład użycia tych zmiennych na przykładowej stronie WWW. Wydruk 27.7. Zmienne obiektów Application i Session
<%Application("VisitorNum")=Application("VisitorNum")+1%>

Zmienne obiektów Application i Session:

Aplikacja uruchomiona: <%=Application("Start")%>

Użytkownik odwiedzający aplikację: <%=Application("VisitorNum")%>

Sesja uruchomiona: <%=Session("Start")%>


Rysunek 27.6. Obiekty ASP Użycie ADO w aplikacjach ASP Obiekt recordset udostępnia do potencjalnego użycia wiele właściwości i metod. W następnym przykładzie użyjemy właściwości EOF (koniec pliku). EOF pozwala na uruchomienie pętli przeglądającej wszystkie rekordy wyniku od pierwszego do ostatniego. Skrypt zamieszczony na wydruku 27.8 otwiera połączenie oraz po wykonaniu kwerendy w pętli przebiega przez rekordy wyniku, wypisując je do wynikowego wyjścia HTML. Wydruk 27.8. Użycie ADO na stronie ASP Rozdział 26.: Przykład użycia ADO

Lista klientów Northwind Traders

Rozdział 26.: Przykład użycia ADO


<% ' Początek skryptu VBScript Dim x Dim dbconn Dim rst ' Zestawienie połączenia Set dbconn=server.createobject("adodb.connection") ' Inicjowanie połączenia z bazą danych dbconn.open "provider=Microsoft.Jet.OLEDB.4.O;" & _ "data source=D:\wwwroot\db\ch27.mdb" ' Wykonanie zapytania set rst=dbconn.execute ("Select * from Customers") ' Używane jako licznik x=1 Do Until rst.eof response.write x & ". " & rst("CompanyName")%>
<%rst.movenext x=x+1 loop dbconn.close ' Koniec skryptu%>
Wykonanie skryptu 27.8 da w rezultacie stronę pokazaną na rysunku 27.7. Rysunek 27.7. Wynik wykonania skryptu ASP używającego ADO Kombinacja ASP, VBScript oraz ADO pozwala na tworzenie złożonych stron WWW opartych o dane zapisane w bazie danych Accessa 2000. W następnej części rozdziału przedstawię przykład zaczerpnięty z własnej praktyki. Przykład: tworzenie strony WWW dostępnej dla członków grupy Jeżeli chcesz stworzyć witrynę WWW dostępną dla określonej grupy użytkowników, chronioną przed niepowołanym dostępem poprzez konieczność zalogowania się, Access 2000 oraz ASP są właściwym rozwiązaniem. Prowadzę lokalną grupę użytkowników Accessa i Visual Basica w Nowym Jorku. Mamy własną witrynę WWW, która znajduje się pod adresem www.nycaccessvb.com. Używa ona ASP do wyświetlania listy członków, listy spotkań i prowadzi bibliotekę programów. Strony ASP mają połączenie do bazy danych zawierającej informacje o członkach. Dodatkowo członkowie mogą po podaniu hasła uaktualniać informacje o sobie oraz przeglądać strony dostępne tylko dla nich, jak na przykład forum o miejscach pracy. Aplikacja ta pozwala ludziom, którzy podali właściwą nazwę użytkownika i hasło, na dostęp do systemu. Po zalogowaniu użytkownika do zmiennej sesji przypisywany jest identyfikator użytkownika, uwalniając go od konieczności wprowadzania własnych danych na kolejnych stronach witryny. Na koniec do bazy wpisywana jest bieżąca data jako data ostatniej wizyty. Aplikacja uruchamia się, gdy użytkownik wczytuje stronę logowania klubu NYC Access VB. Strona ta przedstawiona jest na rysunku 27.8. Rysunek 27.8. Okno logowania Strona logowania jest zwykłą stroną HTML zawierającą formularz, który wywołuje plik ASP. Na wydruku 27.9 zamieszczony jest kod HTML użyty do utworzenia formularza. Wydruk 27.9. Kod HTML do tworzenia kodu logowania

ID

Hasło

Po kliknięciu przez użytkownika przycisku OK uruchomiony zostanie plik login.asp. Skrypt ten sprawdza w bazie danych, czy użytkownik znajduje się na liście członków. Baza zawiera tabelę z polami zawierającymi nazwę użytkownika, hasło, datę ostatniego dostępu oraz inne pola. Na wydruku 27.10 zamieszczono treść pliku login.asp. Wydruk 27.10. Plik ASP login.asp <%@ LANGUAGE--"VBSCRIPT" %> Formularz logowania <% ' Przeznaczenie: wszyscy użytkownicy muszą się zalogować ' Logowanie jest nieudane, jeżeli nie został wprowadzony prawidłowy ' identyfikator użytkownika lub hasło ' Zmienne Dim rst Dim strUserID Dim strPass Dim strSOL Dim strConnect Dim ado_OpenKeyset Dim ado_LockOptimistic ' Argumenty dla obiektu recordset ado_OpenKeyset=1 ado_LockOptimistic=3 ' Przypisanie ciągu połączenia strConnect="provider=Microsoft.Jet.OLEDB.4.O;" & _ "data source=D:\wwwroot\db\ch27.mdb" ' Pobranie danych z formularza do zmiennych strPass=request.form("txtPass") strUserID=request.form("txtID") ' Tworzenie wyrażenia SQL strSOL="SELECT FName, LName, Email, lastLogin, pass, " & _ "Status FROM tblMembers WHERE (Email =' & " "' & strUserID & _ " "' & ")" ' Tworzenie obiektu rst Set rst=server.createobject("ADODB.RECORDSET") ' Otwarcie obiektu rst rst.open strSOL, _ strConnect, ado_OpenKeyset, ado_LockOptimistic ' Sprawdzenie, czy użytkownik podał identyfikator użytkownika i hasło If strUserID="" or strPass="" then Response.Write "Nie podałeś identyfikatora użytkownika " & _ "lub hasła. Proszę poprawić." else ' jeżeli rst.eof (koniec pliku), to znaczy, że nie znaleziono if rst.eof then response.write "Nie ma takiego użytkownika w systemie !!!" else 'Sprawdzenie, czy podano właściwe hasło If rst("pass")= strPass Then ' Hasło prawidłowe ' Tworzymy stronę WWW Response.Write "Witaj " & rst("FName") & _ " " & rst("LName") Response.Write "
" Response.Write "Ostatnio logowałeś się: " & rst("lastLogin") Response.Write "

" & _ "Aktualizacja" & "danych konta " Response.Write "
Forum o pracy tylko dla członków" ' Ustaw czas ostatniego logowania rst.update ("lastlogin"),Date() ' Ustawienie zmiennej sesji Session("User") = strUserID Else ' Nieprawidłowe hasło response.write "Nazwa użytkownika: " & _ strUSerID & " jest OK, Złe hasło!!!" end if end if end if ' Zamknięcie obiektu rst rst.close %> Pierwszą czynnością wykonywaną przez skrypt zamieszczony na wydruku 27.10 jest przygotowanie zmiennych używane w dalszej części skryptu. Następnie przy użyciu danych podanych przez użytkownika w formularzu tworzone jest wyrażenie SQL. Do przechowywania nazwy użytkownika używana jest zmienna strUserId. Wyrażenie SQL, które pobiera informacje o użytkowniku, wygląda następująco: StrSQL="SELECT Fname, LName, Email, lastLogin, pass, " & _ "Status FROM tblMembers WHERE (Email=" & "'" & strUserId & "'" & ")" Jak można zauważyć, kluczem głównym tabeli tblMembers jest pole Email. E-mail użytkownika jest również jego identyfikatorem. Jeżeli użytkownik nie poda identyfikatora lub hasła, za pomocą metody Response.Write wyświetlane jest ostrzeżenie pokazane na rysunku 27.9. Rysunek 27.9. Ostrzeżenie o braku identyfikatora użytkownika lub hasła Jeżeli użytkownik poda właściwą nawę użytkownika, skrypt sprawdza, czy podane jest właściwe hasło. Sprawdzenie to przeprowadzane jest w wierszu: If rst("pass")=strPass Jeżeli hasło jest niewłaściwe, użytkownik jest o tym powiadamiany przy użyciu metody Response.Write (rysunek 27.10). Jeżeli użytkownik wprowadzi właściwe hasło, w zmiennej sesji zapamiętywana jest nazwa użytkownika i uaktualniane jest pole tabeli lastlogin. Poniższy fragment skryptu realizuje te czynności. ' Ustawienie daty ostatniej wizyty rst.update("lastlogin"), Date() ' Ustawienie globalnej zmiennej sesji Session("User") = strUserId Rysunek 27.10. Informacja o błędnym haśle Po autoryzacji użytkownika używamy metody Response.Write do utworzenia strony WWW tylko dla członków grupy. Można również użyć metody Response.Redirect, aby skierować użytkownika na zupełnie inną stronę. Strona ta pokazana jest na rysunku 27.11. Rysunek 27.11. Strona tylko dla członków grupy Po zalogowaniu użytkownika do systemu można dostarczyć do kolejnych stron wszystkie informacje o nim. Dodatkowo, jedną z lepszych cech ASP jest możliwość edycji przez użytkownika informacji o sobie. W naszej sytuacji dajemy użytkownikowi tylko możliwość zmiany hasła. Po zalogowaniu użytkownika do części witryny tylko dla członków dostępna jest opcja zmiany własnych danych. Strona ta pokazana jest na rysunku 27.12. Rysunek 27.12. Strona zmiany hasła przez członków grupy Jest to formularz HTML umożliwiający wprowadzenie i weryfikację hasła. Jej kod HTML przedstawiony jest na wydruku 27.11. Wydruk 27.11. Formularz zmiany hasła

Hasło

Weryfikacja

Formularz przedstawiony na wydruku 27.11 wywołuje plik changepass.asp, który uaktualnia hasło użytkownika i potwierdza je. Wydruk 27.12 zawiera kod źródłowy pliku changepass.asp. Wydruk 27.12. Plik changepass.asp <%@ LANGUAGE="VBSCRIPT" %> Zmiana hasła <% ' Przeznaczenie: sprawdzenie potwierdzenia hasła i zmiana bazy danych ' Jeżeli hasło nie jest identyczne w obu polach tekstowych, przerwij ' Deklaracje Dim rst Dim strPass Dim strVerify Dim strSOL Dim strConnect Dim ado_OpenKeyset Dim ado_LockOptimistic ado_OpenKeyset=1 ado_LockOptimistic=3 ' Przypisanie ciągu połączenia strConnect="provider=Microsoft.Jet.OLEDB.4.O;" & _ "data source=D:\wwwroot\db\ch27.mdb" ' Pobranie danych z formularza strPass=request.form("txtPass") strVerify=request.form("txtVerify") ' Sprawdzenie, czy zgadzają się wartości w polach If strpass <> strVerify then response.write "Nie zgadzają się wartości w " & _ " polach hasła !
" response.write "Proszę powtórzyć." else strSOL="SELECT pass, Status FROM tblMembers " & _ "WHERE (Email =" & "'" & Session("User") & "'" & ")" ' Utworzenie obiektu rst Set rst=server.createobject("ADODB.RECORDSET") rst.open strSOL, _ strConnect,ado_OpenKeyset,ado_LockOptimistic If rst.eof then response.write "Nie ma takiego użytkownika w systemie!!!" else rst.update ("pass"),strVerify Response.Write "Hasło zostało zmienione, " & _ "proszę je zapamiętać !!" end if rst.close end if%> Kod z wydruku 27.12 nie różni się wiele od tego z wydruku 27.10. Na początku należy się upewnić, czy użytkownik wpisał identyczne napisy do obu pól tekstowych i kontynuuje tylko w przypadku takiej zgodności. Następnie przy użyciu zmiennej globalnej User tworzone jest wyrażenie SQL. Jest to przykład utrzymywania stanu sesji przez ASP. Nie ma potrzeby pytać powtórnie użytkownika o jego identyfikator lub wywoływać skomplikowane i obciążające serwer programy CGI-BIN, które potrafiłyby utrzymać stan sesji. Po otwarciu obiektu recordset używamy metody Update w celu uaktualnienia hasła użytkownika w bazie danych na serwerze WWW. Podczas następnego logowania użytkownika należy użyć nowego hasła. Rysunek 27.13 przedstawia ekran potwierdzający zmianę hasła. Rysunek 27.13. Ekran potwierdzający zmianę hasła Na tym zakończymy omawianie tego przykładu. Możesz odwiedzić witrynę http://www. nycaccessvb.com, aby przejrzeć listę witryn WWW używających Accessa 97 lub 2000 jako silnika bazy danych. Mam nadzieję, że ten przykład i cały rozdział pozwoli Ci rozpocząć tworzenie świetnych internetowych aplikacji Accessa 2000. Publikacja w sieci z Accessa 2000 przy użyciu XML Najprawdopodobniej natknąłeś się już na nowe słowo w technologii Internetu: XML lub Extensible Markup Language. XML jest zorientowanym na dane standardem zapisu dokumentów i został zdefiniowany przez konsorcjum W3C. Programiści internetowych baz danych powinni zainteresować się tym sposobem zapisu dokumentów. W tej części rozdziału opiszemy dokumenty XML i użyjemy ich w aplikacji. Podstawy XML XML jest zbiorem reguł tworzenia opisowych znaczników identyfikujących dane, z których zbudowany jest dokument. Mimo że XML jest podobny do HTML, to jest od niego o wiele bardziej rozbudowany. Za pomocą XML tworzy się znaczniki, które używane w dokumencie dzielą go na logiczne fragmenty. Litera X w XML pochodzi od słowa Extensible (rozszerzalny), ponieważ w przeciwieństwie do HTML, który ma ściśle zdefiniowany zbiór znaczników, zbiór znaczników w XML jest nieomal nieograniczony. Znaczniki opisujące te dane tworzy się w momencie, gdy są one potrzebne. Ponieważ programiści baz danych codziennie pracują z danymi, XML jest dla nich bardzo użyteczny. Utwórzmy prosty dokument XML opisujący tabelę Klienci w bazie danych Northwind. Ponieważ XML oparty jest o zestaw znaków Unicode, można do jego stworzenia użyć dowolnego edytora używającego ASCII lub Unicode. Aby rozpocząć tworzenie dokumentu XML wpisz w edytorze poniższy wiersz: Jest to wiersz deklaracji sygnalizujący interpreterowi XML, że jest to dokument XML. Gdy Twoje dokumenty XML będą bardziej skomplikowane, część deklaracji będzie bardziej złożona. Przykładowo można zadeklarować, jakie znaczniki są dopuszczalne w dokumencie lub gdzie znajdują się deklaracje arkusza stylów. Na razie zajmiemy się tylko podstawami. Po deklaracjach należy zdefiniować główny element. Jest on elementem, który będzie opisywany w dokumencie. W dokumencie może występować tylko jeden taki element. Ponieważ opisujemy dane klientów, nasz element główny nazywać się będzie . Następnie należy zdefiniować węzły potomne. Węzły potomne są elementami tworzącymi dane. Utworzymy węzeł potomny do głównego, nazwanego . Wewnątrz każdego węzła klienta mamy węzły potomne zawierające dane. Te węzły mają nazwy zgodne z nazwami pól w tabeli Klienci z bazy danych Northwind. Przykład takiego pliku pokazany jest na wydruku 27.13. Wydruk 27.13. Prosty dokument XML, który opisuje klientów ALFKI Alfreds Futterkiste Maria Anders Sales Representative ANATR Ana Trujillo Emparedados y helados Ana Trujillo Owner ANTON Antonio Moreno Taqueria Antonio Moreno Owner Teraz zapisz plik jako customers.xml. Teraz możemy oddzielić dane od formatowania przy użyciu XML oraz Dynamic HTML. Wypełnimy tabelę HTML danymi XML zapisanymi w pliku customers.xml. Możesz skorzystać z dostępnego w IE 4.0 i nowszych, łączenia danych z pliku XML poprzez applet Javy. Wynik umieszczenia danych XML w tabeli HTML pokazany jest na rysunku 27.14. Aby wczytać XML do strony WWW, utwórz prostą stronę zamieszczoną na wydruku 27.14. Rysunek 27.14. Dołączanie danych XML do strony HTML Wydruk 27.14. Dołączanie danych XML w IE 4 i IE 5 Dołączanie danych XML z pliku na dysku ' +

Dołączanie danych XML z pliku na dysku

ID e/th> Name
Aby przetworzyć plik XML, należy użyć appletu Javy, który jest dostarczany razem z IE 4.0 (można również ściągnąć do ze strony WWW Microsoftu). Dodaj fragment z APPLET z wydruku 27.14 do Twojego pliku HTML i ustaw właściwość URL na ścieżkę lub URL do pliku XML. Następnie należy użyć prostego łączenia Dynamic HTML za pomocą znacznika datasrc="#xmldso" w deklaracji tabeli, gdzie #xmldso jest nazwą obiektu z appletu Javy. Na koniec przypisz właściwości datafld każdego pola tabeli nazwy węzłów potomnych z pliku XML. Gdy zmienisz zawartość pliku XML, wynikowa strona również się zmieni. Programowe tworzenie pliku XML Ponieważ XML jest tak łatwy do tworzenia i używania w aplikacji, utwórzmy własną bibliotekę DLL ActiveX, która utworzy kod XML. Za pomocą tej biblioteki można tworzyć na bieżąco pliki XML używane w witrynach WWW lub aplikacjach. Utwórzmy w VB 6.0 projekt ActiveX DLL o nazwie XML_TOOL z jednym modułem klasowym o nazwie Database. Nasza klasa posiadała będzie tylko jedną metodę, CreateXML. Należy również ustawić w menu Tools, References odwołanie do ADO 2.0. Metoda ta używa ADO do podłączenia się do bazy danych, otwarcia wyniku i zwrócenia danych XML do klienta. Metoda ta wymaga trzech argumentów: nazwy głównego elementu, ciągu połączeniowego i wyrażenia SQL, które należy wykonać. Metoda ta jest zamieszczona na wydruku 27.15. Wydruk 27.15. Programowe tworzenie XML jako komponent VB Public Function CreateXML _ (strEntity As String, strSOLStatement As String, _ strConnectionString As String) As String ' Funkcja tworzy XML z wyniku wykonania kwerendy. ' Używa Recordset ADO i zwraca wynik do aplikacji Dim rst As ADODB.Recordset Dim fld As ADODB.Field Dim strReturn As String On Error GoTo Proc_Err Set rst = New ADODB.Recordset ' Otwarcie obiektu recordset opartego o wyrażenie SQL ' które jest przekazane do metody wraz z ciągiem połączeniowym rst.Open strSQLStatement, StrConnectionString ' Rozpoczynamy tworząc nagłówek z numerem wersji strReturn = "" If rst.EOF And rst.BOF Then 'Jeżeli nie ma danych tworzymy pusty element strReturn = strReturn & vbNewLine & "<" & strEntity & "s/>" Else ' Znacznik otwierający element strReturn = strReturn & vbNewLine & "<" & strEntity & "s>" 'Pętla przebiegająca przez wynik zapytania i umieszczająca go w ' w pliku XML Do Until rst.EOF ' Otwórz element strReturn = strReturn & vbNewLine & "<" & strEntity & ">" ' Każde pole jest zapisywane do pliku ' Jeżeli chcesz mniej pól, wylicz je w wyrażeniu SQL For Each fld In rst.Fields strReturn = strReturn & vbNewLine & "<" & fld.Name & ">" strReturn = strReturn & fld.Value strReturn = strReturn & "" Next fld ' Zamknij element strReturn = strReturn & vbNewLine & "" ' Przejście do następnego elementu rst.MoveNext Loop ' Znacznik kończący element strReturn = strReturn & vbNewLine & "" End If ' Przepisz utworzony tekst do wyniku metody CreateXML = strReturn ' Porządki rst.Close Set rst = Nothing Proc_Exit: Exit Function Proc_Err: ' Prześlij błąd do aplikacji Err.Raise Err, "XML DLL", Err.Description Resume Proc_Exit End Function Teraz uruchomimy nasz komponent ActiveX. Po skompilowaniu DLL utwórz nową aplikację Visual Basica i ustaw odwołanie do naszej biblioteki DLL. Program testujący metodę przedstawiony jest na wydruku 27.16. Trzeci parametr wywołania (”Pubs”) jest nazwą DSN bazy danych na serwerze SQL. Wydruk 27.16. Wywołanie komponentu utworzonego na wydruku 27.15 Private Sub cmdPrintXML Click() Dim xml As XML_Tool.Database Set xml = New XML Tool.Database Debug.Print xml.CreateXML("Publishers", "Select * From Publishers", "Pubs") End Sub Wynik działania programu jest następujący: 0736 New Moon Books Boston MA USA 0877 Binnet & Hardley Washington DC USA Nasza aplikacja testująca drukuje kod XML w oknie uruchamiania, jednak można utworzyć plik XML przy użyciu zwykłych operacji wejścia-wyjścia lub innej techniki. Użyjemy teraz komponentu na stronie ASP. W jednym z ostatnich przykładów ładowaliśmy do strony HTML dane XML. Ten kod XML może być wbudowany w stronę WWW. Użyjmy teraz naszego komponentu, aby dynamicznie utworzyć wbudowany w stronę kod XML, gdy użytkownik zażąda dostępu do strony WWW. Za pomocą VBScript można załadować DLL ze strony WWW i dynamicznie utworzyć kod XML wykorzystywany w aplikacji WWW. Poniższy kod tworzy taką samą jak poprzednio stronę WWW, jednak teraz jest dynamiczna i tworzy XML na bieżąco. Wydruk 27.17. Tworzenie XML w skrypcie ASP <% Dim xml Dim strSOL Dim strConnect Dim strXML Set xml = Server.Create0bject("XML Tool.Database") strSQL="Select * from Customers " strConnect="File Name=c:\jetweb.UDL;" strXML= xml.CreateXML("Customer", cstr(strSOL), cstr(strConnect)) %> <%=strXML%> Tworzenie wykresów przy użyciu formantu Wykres Rozdział 25. zawiera wprowadzenie do komponentów sieciowych Office i wyjaśnia, jak używać ich w Accessie 2000 oraz Visual Basicu. W rozdziale 26. objaśniliśmy sposób ich użycia na stronach dostępu do danych. Co zrobić, jeżeli przeglądarka, której używasz, nie obsługuje formantów ActiveX? Formant Wykres pozwala na użycie rysunków GIF dla przeglądarek nie obsługujących ActiveX. Za pomocą prostej kwerendy przestawnej z bazy danych Northwind utworzymy niezwiązany formularz na stronie ASP. Utworzymy plik global.asa, aby zarządzać plikami GIF (wydruk 27.18). Wydruk 27.18. Tworzenie wykresu w pliku GIF na serwerze W pliku ASP utworzymy tablicę aHeaders, w której umieszczamy nazwy nagłówków, w tym przykładzie cztery kwartały roku podatkowego. Następnie po otwarciu wyniku ADO opartego na zapisanej kwerendzie krzyżowej o nazwie qryQuarterlySales, wypełniamy tablicę aValues wartościami pól wyniku. Pełny kod przedstawiony jest na wydruku 27.19. Wydruk 27.19. Praca z komponentem sieciowym Wykres z pakietu Office <%@ language="vbscript" %> <% Dim ChartSpace1, c, aHeaders(3), aValues(3) Dim rst ' Tworzenie tablicy nagłówków wykresu aHeaders(0) = "01" aHeaders(1) = "02" aHeaders(2) = "03" aHeaders(3) = "04" ' Otwarcie wyniku kwerendy krzyżowej z bazy Notrhwind ' i wpisanie jej wartości do słupków wykresu Set rst=Server.Create0bject("ADODB.Recordset") rst.Open "qry0uarterlySales", "File Name=" & Server.MapPath("Jet.UDL") aValues(0) = rst![Otr 1] aValues(1) = rst!(Otr 2] aValues(2) = rst![Otr 3] aValues(3) = rst![Otr 4] ' – Tworzenie niewidocznej wersji komponentu wykres Set ChartSpace1 = Create0bject("OWC.Chart") Set c = ChartSpacel.Constants ChartSpacel.Border.Color = c.chColorNone ChartSpacel.Charts.Add ChartSpacel.Charts(0).Type = _ ChartSpacel.Constants.chChartTypeColumnClustered ChartSpacel.Charts(0).SeriesColleCtion.Add ChartSpacel.Charts(0).Series0ollection(0).Caption = "Sales" ChartSpacel.Charts(0).Series0ollection(0).SetData _ c.chDimCategories, c.chDataLiteral, aHeaders ChartSpacel.Charts(0).SeriesCollection(0).SetData _ c.chDimValues, c.chDataLiteral, aValues ChartSpacel,Charts(0).HasLegend = True '—- Pobranie nazwy tymczasowego pliku z global.asa szFilename = Session("FileSystem").GetTempName & ".gif" '—- Eksport pliku GIF z wykresu ChartSpacel.ExportPicture "D:\ntstuff\WebStuff\" & _ szFilename, "gif", 600, 512 '—- Tworzenie łącza do pliku GIF Response.Write " [RG1]Co to jest? Poprawiłem (PG) 20 Spis treści 19 26 Część I ? Projektowanie bazy danych 25 Rozdział 1. ? Co nowego w Accessie 2000 44 Część I ? Projektowanie bazy danych 43 Rozdział 2. ? Planowanie procesu rozwoju 52 Część I ? Projektowanie bazy danych 51 Rozdział 3. ? Projekt bazy danych i normalizacja 76 Część I ? Projektowanie bazy danych 75 Rozdział 4. ? Zaawansowane kwerendy 86 Część I ? Projektowanie bazy danych 87 Rozdział 5. ? Jet 4.0 – silnik baz danych Microsoft 88 Część I ? Projektowanie bazy danych 87 Rozdział 5. ? Jet 4.0 – silnik baz danych Microsoft 102 Część II ? Dostęp do danych 103 Rozdział 6. ? Wprowadzenie do obiektów danych Active X 122 Część II ? Dostęp do danych 123 Rozdział 7. ? Zaawansowane ADO 124 Część II ? Dostęp do danych 123 Rozdział 7. ? Zaawansowane ADO 136 Część III ? Interfejs użytkownika 135 Rozdział 8. ? Projektowanie formularza 158 Część III ? Interfejs użytkownika 159 Rozdział 9. ? Rozbudowa formularzy przy użyciu formantów ActiveX 186 Część III ? Interfejs użytkownika 185 Rozdział 10. ? Tworzenie raportów 186 Część III ? Interfejs użytkownika 187 Rozdział 10. ? Tworzenie raportów 206 Część IV ? Tajniki VBA 207 Rozdział 11. ? Tworzenie obiektów przy użyciu modułów klas 220 Część IV ? Tajniki VBA 219 Rozdział 12. ? Usuwanie błędów w aplikacjach Accessa 238 Część IV ? Tajniki VBA 239 Rozdział 13. ? Profesjonalna obsługa błędów 264 Część IV ? Tajniki VBA 265 Rozdział 14. ? Optymalizacja aplikacji 266 Część IV ? Tajniki VBA 265 Rozdział 14. ? Optymalizacja aplikacji 280 Część V ? Access i architektura klientserwer 279 Rozdział 15. ? Wprowadzenie do projektów programu Microsoft Access 294 Część V ? Access i architektura klientserwer 295 Rozdział 16. ? Tworzenie interfejsu użytkownika dla Microsoft SQL Server 320 Część V ? Access i architektura klientserwer 319 Rozdział 17. ? Interfejs Access’a 2000 do Oracle’a 280 Część V ? Access i architektura klientserwer 281 Rozdział 15. ? Wprowadzenie do projektów programu Microsoft Access 334 Część VI ? Współoperatywność 333 Rozdział 18. ? Użycie automatyzacji Active X 362 Część VI ? Współoperatywność 363 Rozdział 19. ? Integracja z Office 2000 392 Część VI ? Współoperatywność 391 Rozdział 20. ? Użycie Visual Basic z Access’em 334 Część VI ? Współoperatywność 335 Rozdział 18. ? Użycie automatyzacji Active X 402 Część VII ? Zagadnienia wielodostępu 403 Rozdział 21. ? Zagadnienia wielodostępu, serwer plików, blokowanie 422 Część VII ? Zagadnienia wielodostępu 423 Rozdział 22. ? Replikacja i JRO 440 Część VII ? Zagadnienia wielodostępu 441 Rozdział 23. ? Bezpieczeństwo 406 Część VII ? Zagadnienia wielodostępu 405 Rozdział 21. ? Zagadnienia wielodostępu, serwer plików, blokowanie 458 Część VIII ? Publikowanie w sieci za pomocą Access’a 2000 459 Rozdział 24. ? Konfiguracja serwera WWW dla publikowania w sieci WWW 466 Część VIII ? Publikowanie w sieci za pomocą Access’a 2000 465 Rozdział 25. ? Przenoszenie Access’a 2000 do sieci WWW 476 Część VIII ? Publikowanie w sieci za pomocą Access’a 2000 475 Rozdział 26. ? Użycie stron dostępu do danych 498 Część VIII ? Publikowanie w sieci za pomocą Access’a 2000 489 Rozdział 27. ? Publikowanie w sieci przy użyciu Access’a 2000 i Active Server 504 Część VIII ? Publikowanie w sieci za pomocą Accessa 2000 Rozdział 27. ? Publikowanie w sieci przy użyciu Accessa 2000 i Active Server Pages 503 504 D:\ksiazki\Access 2000 - Księga eksperta\Access 2000 - Księga eksperta.doc