background image

 

Rozdział 21 

Reguły logiki aplikacji w aplikacjach 
Delphi 

W rozdziale tym omawiamy aplikacyjną stronę udanej implementacji reguł logiki 
aplikacji. Jak to już powiedziałem w rozdziale o regułach logiki aplikacji 
bazujących na serwerze, w moim głębokim przekonaniu reguły te powinny być - 
jeśli to tylko możliwe - implementowane po serwerowej stronie aplikacji. Jednak 
w realnych aplikacjach nieuniknione będzie uzupełnianie reguł logiki aplikacji 
zrealizowanych po stronie serwera regułami osadzonymi w oprogramowaniu 
pośredniczącym lub klienta. Chciałbym wierzyć,  że pewnego dnia między 
serwerami baz danych, produktami middleware i narzędziami do tworzenia 
oprogramowania zaistnieje taki synergizm, iż problem ten zniknie całkowicie 
i programista  przestanie  zajmować się tym, gdzie jego reguły są 
zaimplementowane, a skoncentruje się na tym, jak są one zaimplementowane.  

Wśród programistów z długim stażem występuje skłonność do umieszczania 
znacznej części reguł logiki aplikacji w 

samej aplikacji. Świat narzędzi 

programistycznych jest dla nich terytorium już „oswojonym”, natomiast 
platformom DBMS tradycyjnie brakowało owych wyszukanych narzędzi do 
wdrażania reguł logiki aplikacji, bez których aplikacje na wysokim poziomie nie 
mogą się obejść.  

Abstrahując jednak od wszelkich skłonności, przeniesienie reguł logiki aplikacji 
hurtem do niej samej nie jest - jak już powiedziałem - żadnym rozwiązaniem. 
Środowisko programistów powinno zmusić producentów DBMS i oprogramo-
wania pośredniczącego do stworzenia wszechstronnych interfejsów dla reguł 
logiki aplikacji - czyli takich interfejsów, jakich potrzebują profesjonalne 
aplikacje. Odpowiedzią nie może być zwykle „machnięcie ręką” i wyproduko-
wanie banalnego rozwiązania, bazującego na pośledniej technologii. Najlepszym 
podejściem byłoby skłonienie producentów do tego, by wyszli na przeciw 
potrzebom swych klientów - by dostarczyli takiego wsparcia reguł logiki aplikacji, 
jakiego użyć można w prawdziwych aplikacjach. Zanim to nie nastąpi, systemy 
klient/serwer będą nadal równie nieodporne na naruszenia reguł logiki aplikacji, co 
ich niegdysiejsi plikowi odpowiednicy. 

Ku chwale producentów DBMS i oprogramowania pośredniczącego przyznać 
trzeba jednak, że w korygowaniu swych strategii reguł logiki aplikacji poczynili 
ostatnio spore postępy. W przeszłości większość implementacji reguł logiki 

background image

628 

Część IV 

aplikacji bazujących na serwerze charakteryzowała się całkowitą „hermetycz-
nością” - były bezpieczne - lecz dla programisty „nieprzyjazne”. Programiści mieli 
na przykład problemy ze skłonieniem obiektów bazy danych i obiektów aplikacji 
do bezkonfliktowej współpracy. Jeśli na przykład jako źródło wartości dla 
wstawianego wiersza użyty został domyślny obiekt Sybase, to skąd aplikacja 
mogłaby o tym wiedzieć i w jaki sposób miałaby wyświetlić na ekranie domyślne 
wartości kolumn, gdyby użytkownik dodał nowy wiersz do tabeli? Programiście 
pozostawał tylko wybór mniejszego zła - albo całkowite ignorowanie bazujących 
na serwerze reguł logiki aplikacji i ponowne implementowanie ich w aplikacjach, 
albo rezygnacja z 

synchronizowania widoku aplikacji na ekranie z 

jej 

bazodanowymi partnerami. Żadna z tych możliwości nie była szczególnie 
pociągająca i, jak zauważył kiedyś Jerry Garcia, „wybieranie mniejszego zła jest 
także wybieraniem zła”. 

Na szczęście w 

ostatnich czasach producenci DBMS i 

oprogramowania 

pośredniczącego stają się coraz bardziej przyjaźni wobec użytkowników. 
Rozsądne projektowanie reguł logiki aplikacji stało się obecnie łatwiejsze niż 
kiedykolwiek. Jednocześnie narzędzia do projektowania aplikacji baz danych, 
takie jak Delphi, stają się coraz bardziej świadome istnienia swych 
„współrozmówców” w bazach danych i oprogramowaniu pośredniczącym i coraz 
więcej o 

nich wiedzą. W 

rezultacie narzędzia programistyczne i 

produkty 

serwerowe zaczynają jednoczyć się w dążeniu do zaspokojenia potrzeb ludzi 
W miarę, jak platformy DBMS, produkty middleware i narzędzia programistyczne 
będą się uczyć ze sobą współpracować, implementowanie rozsądnej strategii reguł 
logiki aplikacji będzie coraz łatwiejsze. 

Jednak niezależnie od tego, w którą stronę zmierza postęp, na razie musimy 
borykać się z tym, co dostępne jest tu i teraz. Aktualna sytuacja jest zaś taka, że 
najprawdopodobniej będziemy musieli zaimplementować część reguł logiki 
aplikacji w samej aplikacji. Jak już powiedziałem w rozdziale o regułach po 
stronie serwera, podejście, jakie ja zwykle przyjmuję, jest następujące: na 
platformie DBMS implementuję całą tę strategię reguł logiki aplikacji, którą mogę 
tam zaimplementować, 

a potem 

w miarę potrzeby uzupełniam ją 

w oprogramowaniu  pośredniczącym (middleware) lub na kliencie. I nie ma tu 
znaczenia, czy mamy do czynienia z 

tabelami bazy Paradox, czy też 

najprawdziwszą implementacją klient/serwer. To, czego nie mogę zaimplemento-
wać na serwerze, implementuję  w middleware  i w kliencie.  Innymi  słowy, tymi 
konstrukcjami wypełniam luki w implementacji bazującej na serwerze. 

Rozdział ten zajmuje się aplikacyjną stroną prawidłowej implementacji reguł 
logiki aplikacji. Dokonuje przeglądu różnych sposobów planowania efektywnej 
strategii reguł logiki aplikacji w naszym programie. Dowiemy się w nim na 
przykład,  że w Delphi są cztery główne poziomy projektowania bazujących na 
oprogramowaniu reguł logiki aplikacji: poziom typu danych, poziom 

background image

 Rozdział 21 Reguły logiki aplikacji w aplikacjach Delphi 

629

 

komponentów, poziom 

TField

 i poziom 

TDataSet

. Każdy z nich omówię 

szczegółowo, dzięki czemu Czytelnik bez trudu zrozumie, jak je stosować we 
własnych aplikacjach.  

Typy reguł logiki aplikacji 

Reguły logiki aplikacji dzielą się na dwa wyraźnie odmienne typy: proste reguły 
logiki aplikacji i złożone reguły logiki aplikacji. Proste zapewniają prostą 
integralność encji. Gwarantują one na przykład,  że dane liczbowe trafią do pola 
liczbowego, kolumna dat zawierać będzie tylko daty i tak dalej. Proste reguły mają 
zastosowanie niezależnie od tego, czym dana aplikacja jest lub do czego baza 
danych jest używana. 

Reguły złożone dotyczą bardziej zaawansowanych aspektów dostępu do bazy 
danych - pozwalają one zapewnić integralność referencyjną. Zwykle są przy tym 
specyficzne dla danej bazy danych lub nawet konkretnej tabeli. 

W książce tej terminu reguły logiki aplikacji używam w jego najszerszym sensie. 
Innymi słowy wszystko, o czym mówię, dotyczy zarówno reguł prostych, jak 
i złożonych. Wszystko, począwszy od prostego sprawdzenia poprawności danych, 
a na skomplikowanej integralności relacyjnej skończywszy, zmieści się pod 
„parasolem” reguł logiki aplikacji. Chociaż z generalnego omówienia reguł logiki 
aplikacji mógłbym wyłączyć techniki sprawdzania poprawności danych, to nie 
widzę 

żadnych korzyści z 

takiego rozwiązania. Metody stosowane 

w implementacji prostych reguł logiki aplikacji są takie same, jak metody używane 
do tworzenia reguł  złożonych. Dlatego moje podejście polega na omówieniu 
efektywnego projektowania reguł logiki aplikacji z 

perspektywy ogólnej. 

Niezależnie od tego, czy są to reguły proste, czy złożone, wszystkie one zasługują 
na jednakową uwagę. 

Delphi dostarcza kilku sposobów konstruowania prostych reguł logiki aplikacji bez 
żadnego kodowania i oferuje zgrabny komplet narzędzi do konstruowania reguł 
złożonych z użyciem minimalnej ilości kodu. W rozdziale tym przeanalizujemy, 
z perspektywy aplikacji, oba typy reguł. 

Dwie zasady dla reguł logiki aplikacji 

Pierwszym poziomem implementacji reguł logiki aplikacji po stronie klienta jest 
poziom typu danych. Trzeba mieć zawsze na uwadze dwie podstawowe zasady 
ilustrujące dobitnie doniosłość  właściwego wyboru typu danych. Jeśli będziemy 
ich przestrzegać, to zawczasu unikniemy wielu typowych problemów, jakie 
niekiedy gnębią mniej doświadczonych programistów.  

background image

630 

Część IV 

Zasada pierwsza 

Pierwsza zasada ustanawiania reguł logiki aplikacji po stronie klienta brzmi: 

Przede wszystkim używaj odpowiednich typów danych spośród dostępnych 
w bazie. 
 

VCL w Delphi narzuca kilka prostych, wbudowanych ograniczeń zależnych od 
typu danych, jakie kolumna reprezentuje. Na przykład komponenty skojarzone 
z danymi (data-aware) nie będą tolerować niepoprawnych dat w kolumnach o typie 
„data”, znaków alfabetycznych w polach liczbowych, lub niewłaściwych wartości 
w polach logicznych. By narzucić te ograniczenia, nie musimy tworzyć  żadnego 
kodu - Delphi zrobi to automatycznie. Po prostu trzeba od samego początku 
używać odpowiednich typów danych.  

Wśród programistów-weteranów zauważa się skłonność do nadużywania typów 
łańcuchowych przy tworzeniu baz danych. Widziałem na przykład tabele 
zawierające kolumny z datami, które były zdefiniowane z pomocą  łańcuchowych 
typów danych. Widziałem także dane liczbowe przechowywane w 

polach 

znakowych. Jeśli kolumna ma zawierać daty i tylko daty, to zdefiniujmy ją 
korzystając z jakiegoś typu daty. Jeśli pole może zawierać tylko liczby, to 
zdefiniujmy je przy pomocy numerycznego typu danych. Nie ma powodu, by 
wartości numeryczne trzymać w kolumnach alfabetycznych. 

Inna sytuacja, w której używanie właściwych typów danych ma dla poprawnego 
projektowania reguł logiki aplikacji zasadnicze znaczenie, związana jest 
z kolumnami  zawierającymi wartości sekwencyjne. Choć niewątpliwie 
moglibyśmy stworzyć system numerowania sekwencyjnego w kodzie Object 
Pascal, to najlepiej będzie od razu użyć typów danych, które z samej swej natury 
są sekwencyjne. Na przykład Sybase i Microsoft wspierają stosowanie kolumn 
indentyfikacyjnych
  (identity columns) - specjalnych kolumn, automatycznie 
inkrementowanych przez serwer. Korzystając z autoinkrementowanych typów 
danych unikamy konieczności samodzielnego generowania liczb sekwencyjnych 
i zapewniamy sobie, że podstawowa reguła logiki aplikacji, o która nam chodzi - 
liczby w kolumnie Y tablicy X muszą być sekwencyjne - zostanie zrealizowana 
praktycznie bez żadnego wysiłku z naszej strony. 

Zasada druga 

Druga podstawowa zasada obowiązująca przy implementowaniu bazujących na 
aplikacji reguł logiki aplikacji brzmi: 

Używaj takich komponentów Delphi, które najlepiej odpowiadają bazowym typom 
danych.
 

background image

 Rozdział 21 Reguły logiki aplikacji w aplikacjach Delphi 

631

 

Błędem, który w tej dziedzinie programiści robią najczęściej, jest zbyt szerokie 
stosowanie komponentów do wprowadzania normalnego tekstu. Tego rodzaju 
komponenty (takie jak 

DBEdit

TEdit

 i 

TMaskEdit

) mogą umożliwić 

wpisanie w pole wartości nieodpowiednich dla typu danej, z jaką komponent jest 
skojarzony. Unikamy tego używając w 

pierwszym rzędzie odpowiednich 

komponentów. 

Na przykład nie powinniśmy używać 

DBEdit

 dla pól logicznych. Pole to może 

mieć tylko dwie wartości: 

True

 i 

False

. Dlatego zamiast pola edycyjnego 

użyjmy przycisku przełącznika (checkbox), przycisku opcji (radio button) lub listy 
rozwijanej (drop-down list). Nie używajmy także 

DBEdit

 dla pól, których 

wartości są tylko do odczytu; zamiast niego użyjmy komponentu DBText. Chroni 
to zasoby systemowe i oszczędza kłopotu z ustawianiem właściwości 

ReadOnly

 

komponentu. Podobnie 

DBEdit

 nie powinniśmy używać dla kolumn liczbowych, 

które mogą mieć tylko niewielką ilość dopuszczalnych wartości - tutaj lepszy 
będzie 

DBRadioGroup

. Tabela 21.1 podaje, których komponentów najlepiej 

używać z rozmaitymi podstawowymi typami danych. 

Tabela 21.1. Typy danych w kolumnach i odpowiadające im komponenty VCL 

Typ danych 

Komponenty 

Boolowski 

DBCheckBox

DBRadioGroup

DBComboBox

DBListBox

 

Data 

DBEdit

Calendar

SpinEdit

DataTimePicker 

Liczbowy (pozwalający na 
wprowadzanie dużych ilości wartości) 

DBEdit

SpinEdit 

Liczbowy (pozwalający na 
wprowadzenie jedynie niewielkiej ilość 
wartości) 

DBRadioGroup 

Łańcuch (pozwalający na wprowadzanie 
dużych ilości wartości) 

DBEdit 

Łańcuch (pozwalający na wprowadzanie 
jedynie niewielkiej ilości wartości) 

DBComboBox, DBListBox 

background image

632 

Część IV 

WSKAZÓWKA: 

Typ kontrolki, używanej dla danego pola, można skonfigurować redagując 
właściwość 

TControlClass

 w Eksploratorze Baz Danych (Database Explorer). 

Po ustawieniu tej właściwości przeciągnięcie 

TField

 z Edytora Pól (Fields 

Editor) na formularz spowoduje utworzenie wybranego komponentu.  

Podstawowa zasada polega tu na użyciu takiego komponentu, który 
w maksymalnym stopniu zapewnia poprawność wprowadzanych do niego danych, 
zapobiegając przy tym wprowadzaniu wartości poprawnych. 

Komponenty pochodne 

Drugim poziomem implementacji reguł logiki aplikacji po stronie programu jest 
warstwa komponentów pochodnych (custom component). Dzięki specyficznej, 
opartej na komponentach architekturze Delphi, na rynku pojawił się cały szereg 
wysokiej jakości narzędzi i bibliotek umożliwiających włączanie reguł logiki 
aplikacji bezpośrednio do komponentów. Robi się to zwykle przez dziedziczenie 
nowych komponentów ze znajdującej się w Delphi klasy komponentów 

DataSet

 

i wbudowywanie do komponentów potomnych wymaganej reguły logiki aplikacji. 

Narzędzia te umożliwiają na ogół specyfikowanie wszystkiego, co tylko może być 
potrzebne - od indywidualnych masek wprowadzania dla pól, do złożonych 
zależności między tabelami. Zwłaszcza w przypadku Delphi 1.0 stanowi to bardzo 
praktyczne podejście do konstruowania racjonalnych implementacji reguł logiki 
aplikacji. 

Ujemną stroną takiego podejścia jest fakt, że ponieważ programiści nie muszą 
koniecznie używać tych właśnie komponentów, to możliwe jest budowanie 
aplikacji Delphi nie respektujących wbudowanych w nie reguł logiki aplikacji. Co 
więcej, ponieważ podejście „komponentowe” jest rozwiązaniem specyficznym 
tylko dla Delphi, to aplikacje stworzone z użyciem innych narzędzi (z wyjątkiem 
Borland C++ Builder) nie mogą wykorzystywać reguł logiki aplikacji, osadzonych 
w tego rodzaju potomkach 

TDataSet

.  

Zatem, jeśli chodzi o ten typ narzędzi, moja rada jest taka sama, jak w ogólnym 
przypadku implementacji reguł logiki aplikacji po stronie programu: nawet jeśli 
zdecydujemy się na użycie jednej z nich, to nadal jak największą część naszej 
strategii reguł logiki aplikacji powinniśmy implementować na samym DBMS, zaś 
komponentów pochodnych używać jako sposobu na wzbogacenie implementacji. 

background image

 Rozdział 21 Reguły logiki aplikacji w aplikacjach Delphi 

633

 

Właściwości TField a reguły logiki aplikacji 

Trzecim poziomem strategii reguł logiki aplikacji po stronie klienta jest poziom 
właściwości 

TField

. Reguły logiki aplikacji odnoszą się zwykle do bardziej 

złożonych jednostek niż same tylko maski pól lub etykiety do wyświetlania. Mimo 
to liczne właściwości klasy komponentu 

TField

 związane są w pewien sposób 

z poprawnym implementowaniem reguł logiki aplikacji. Właściwości takie jak 
atrybut maski edycyjnej w 

TField

 związane są przez to, że wymuszają zgodność 

danych, które kolumna otrzymuje, z określonym formatem. Jest to wspomniana 
wcześniej prosta odmiana reguł logiki aplikacji. Na bazie takich prostych reguł 
logiki aplikacji budujemy strukturę reguł bardziej zaawansowanych, jak na 
przykład te, które zapewniają integralność referencyjną pomiędzy dwiema 
tabelami lub dostarczają danej kolumnie wartości domyślnych. Udana 
implementacja reguł logiki aplikacji wymaga poświęcenia wielkiej uwagi 
szczegółom. 

Istnieją dwa sposoby implementowania prostych reguł logiki aplikacji poprzez 
odpowiednie ustawianie właściwości komponentu 

TField

. Pierwsza polega na 

użyciu Słownika danych (Data Dictionary) Delphi i ustawieniu odpowiednich 
właściwości 

TField

 z użyciem Zestawów atrybutów (Attribute Sets). Druga to 

samodzielne ustawianie tychże właściwości 

TField

 w istniejących w naszej 

aplikacji komponentach 

DataSet

. Choć obie sprowadzają się w istocie do tego 

samego - specyfikowane przez nasz Zestawy atrybutów 

TField

 staja się 

ostatecznie częścią komponentów 

TField

 w naszej aplikacji - to preferowaną 

opcją winno być  użycie Słownika danych do definiowania naszych ustawień 

TField

. Określanie właściwości 

TField

 z pomocą  Słownika danych jest 

bardziej elastyczne i 

ma ogólniejsze zastosowanie, niż robienie tego za 

pośrednictwem Edytora pól (Field Editor) komponentów 

DataSet

. To, czego 

w słowniku tym nie można zdefiniować lub czego definiować w nim nie ma sensu, 
można ustawić w samych komponentach Da

t

aSet. Obie te metody omówię 

szczegółowo po to, by można było w pełni ocenić korzyści związane z każdym 
z tych podejść.  

Importowanie informacji do Słownika 

Informacje słownikową możemy do Słownika danych Delphi importować 
bezpośrednio z naszej wyjściowej bazy danych. Ograniczenia, wartości domyślne, 
typy danych i inne wymagane informacje z naszego serwera zostaną wtedy 
przeniesione do słownika  en masse. Oszczędza to kłopotu z odtwarzaniem 
w słowniku więzów bazujących na serwerze i pomaga utrzymać serwerowe 
i aplikacyjne reguły logiki aplikacji w stanie zsynchronizowanym. By importować 
informacje z bazy danych do Słownika danych należy wykonać następującą 
procedurę: 

background image

634 

Część IV 

1.  W Eksploratorze baz danych (Database Explorer) kliknij fiszkę 

Dictionary

, po 

czym rozwiń gałąź 

Databases

.  

2. Wybierz bazę danych, która mieścić  będzie informacje dla Słownika danych. 

Informacje te przechowywać można albo w nowej słownikowej bazie danych, 
którą rejestrujemy poprzez opcję menu 

Dictionary

\

New

, lub w bazie istniejącej, 

takiej jak baza danych DBDEMOS dostarczana wraz z Delphi. 

3. Kliknij opcjê 

Import from Database

 w menu 

Dictionary

 Eksploratora.  

4. Po wyświetleniu okna dialogowego 

Import

 

Database

 wybierz alias BDE, 

odpowiadający twej bazie danych, i kliknij 

OK

Importowanie naszej bazy danych do Słownika danych Delphi wprowadza do 
niego wszystkie występujące w niej więzy i inne informacje z poziomu pól. 
Wprowadza również domeny ze związanymi z nimi więzami jako Zestawy 
atrybutów (Attribute Set). Dzięki opisanemu procesowi, importowanej informacji 
ze słownika (oraz wszelkich dokonanych w niej zmian) można będzie użyć 
w naszej aplikacji Delphi. Jeśli na przykład importowaliśmy kolumnę, dla której 
w naszej bazie danych jest zdefiniowane CHECK, to więzy te pojawią się również 
w aplikacjach Delphi, odwołujących się do tejże kolumny. Zatem nasza aplikacja, 
zamiast dopiero reagować na odrzucenie przez ograniczenie w 

serwerze 

wprowadzonej już, niepoprawnej wartości, sama zapobiegać  będzie 
przedostawaniu się nieodpowiednich danych do serwera. 

Tworzenie własnych zestawów atrybutów 

Prócz importowania gotowych zestawów atrybutów z baz danych, możemy 
tworzyć zestawy własne i wiązać je z kolumnami w naszych tabelach. Aby 
skonstruować i wykorzystać swój własny zestaw atrybutów, należy wykonać 
następujące czynności: 

1. Prawym klawiszem myszy kliknij gałąź 

Attribute

 

Sets

 w karcie 

Dictionary

 

i z menu wybierz 

New

2. Wpisz nazwę nowego zestawu atrybutów. 

3.  Skonfiguruj te właściwości 

TField

, które powinny być wyspecyfikowane. 

4. Kliknij przycisk 

Apply

 Eksploratora baz danych, aby je zapamiętać. 

5. Rozwiń gałąź 

Database

 na karcie 

Dictionary

 i kliknij tę kolumnę tabeli, z którą 

chciałbyś powiązać swój zestaw atrybutów. 

6. Na karcie 

Definition

 Eksploratora kliknij listę rozwijaną 

Attribute

 

Set

 i wybierz 

swój nowy zestaw atrybutów. 

7. Kliknij przycisk 

Apply

 Eksploratora, aby zapamiętać dokonane zmiany. 

background image

 Rozdział 21 Reguły logiki aplikacji w aplikacjach Delphi 

635

 

Przy pomocy zestawów atrybutów można ustawić wiele atrybutów 

TField

Słownik danych Delphi stanowi bardzo wielkie ułatwienie w definiowaniu reguł 
logiki aplikacji za pośrednictwem właściwości 

TField

. Zaleta definiowania reguł 

logiki aplikacji nie w samych komponentach DataSet, a w Słowniku danych polega 
na tym, że reguły ustanowione w słowniku mogą być wykorzystywane w każdej 
aplikacji Delphi, odwołującej się do odpowiednich tabel. Zapewnia to tę samą 
korzyść, co podejście przyjęte przez niektórych producentów narzędzi baz danych 
i polegające na wbudowywaniu reguł logiki aplikacji w komponenty pochodne - 
jednak bez ujemnych stron wynikających ze stosowania obcego kodu. 

Definiowanie reguł logiki aplikacji z użyciem TField 

Poza wykorzystaniem Słownika danych Delphi do definiowania atrybutów 

TField

, reguły logiki aplikacji można definiować również  używając samych 

komponentów 

TField

. Delphi dodaje komponenty 

TField

 do klasy formularza 

wówczas, gdy z menu 

Edytora

 

pól

  (Field Editor) zbioru danych (DataSet

wybierzemy opcję 

Add

 

fields

. Gdy w ten sposób tworzymy komponenty 

TField

w Inspektorze obiektów (Object Inspector) odzwierciedlone zostają wszystkie 
atrybuty, jakie zdefiniowaliśmy w Słowniku danych. 

Aby ustawić reguły logiki aplikacji bazujące na 

TField

, można skorzystać 

z następującej procedury: 

1. Wywołaj 

Edytor pól

, dwukrotnie klikając komponent 

DataSet

  (

TTable

TQuery

 lub 

TStoredProc

).  

2. Naciśnij CTRL+A, aby utworzyć definicję 

TField

 dla pól komponentu 

DataSet

3.  Kliknij po kolei w każdy z nich i sprawdź/ustaw ich właściwości w Inspektorze 

obiektów. 

Required 

Jedną z najważniejszych spośród tych właściwości 

TField

, które można ustawiać 

w Inspektorze obiektów, jest właściwość 

Required

. Określa ona, czy dane pole 

musi mieć wartość. Przykład sytuacji, w której trzeba będzie zmienić domyślną 
wartość tej właściwości mamy wtedy, gdy serwer dostarcza wartości dla klucza lub 
innej kolumny 

NOT NULL

. Ponieważ występowanie wartości w tej kolumnie jest 

obowiązkowe na serwerze, to Delphi zakłada, że jest ono obowiązkowe i w samej 
aplikacji, zatem wartością domyślną właściwości 

Required

 w 

TField

 staje się 

True

. Jest to jednak zbędne, skoro wartości dla tego pola dostarcza serwer, a co 

więcej - uniemożliwi poprawne działanie aplikacji. Przełączenie 

Required

 na 

False

 przerzuci obowiązek zapewnienia, że pole otrzyma swą wartość, 

z powrotem na serwer, czyli tam gdzie i tak jest on wykonywany. 

background image

636 

Część IV 

Pola obliczane 

Pola obliczane  są  użyteczne w wielu sytuacjach, począwszy od zwykłego 
dostarczania wartości do pól, a na wykonywaniu skomplikowanych obliczeń 
z użyciem pól tabeli skończywszy. Używając mechanizmu pól obliczanych Delphi 
możemy wykonywać operacje matematyczne, wyszukiwanie w 

tabelach, 

sprawdzanie poprawności danych i tak dalej. Pola obliczane są szczególnie 
przydatne w przypadku tych danych, które musimy wyświetlać, lecz których nie 
musimy przechowywać. 

Aby utworzyć pole obliczane, trzeba wykonać dwie podstawowe czynności: 

1. Zdefiniować pole w Edytorze pól (Fields Editor) dla danego komponentu 

DataSet

2. Przypisać polu wartości w 

procedurze 

OnCalcFields

 komponentu 

DataSet

A oto kroki, które trzeba wykonać przy tworzeniu pola obliczanego: 

1. Wyświetl Edytor pól dla danego komponentu 

DataSet

, klikając komponent 

dwukrotnie. 

2.  Kliknij prawym klawiszem myszy listę pól i z menu kontekstowego wybierz 

New

 

field

3.  W oknie dialogowym 

New Field

 wpisz nazwę, jaką chcesz nadać nowemu polu 

obliczanemu, wybierz jego typ (Type) danych i w grupie pól opcji 

Field type

 

kliknij pole 

Calculated

4. Zakończ definiowanie klikając 

OK

. Po powrocie do Edytora pól powinniśmy 

w Inspektorze obiektów Delphi zobaczyć wylistowane właściwości nowego 
pola. Zauważmy, że właściwość 

Calculated

 ustawiona jest na 

True

5.  Po zdefiniowaniu pola można już zaprogramować zdarzenie 

OnCalcFields

 

dla naszego 

DataSet

, które nowemu polu przypisuje wartość. Oto przykład 

takiego przypisania: 

taORDERSOrderDateTime.Value := Now; 

Powyzsza linia kodu przypisuje polu obliczanemu o nazwie 

taORDERSOrder 

DateTime

 wartość dostępnej w Delphi funkcji 

Now

, czyli bieżącą datę i czas. 

Pola obliczane są szczególnie użyteczne przy wykonywaniu ustalonych obliczeń 
obejmujących kolumny tabeli. Pola obliczanego moglibyśmy na przykład użyć do 
zakodowania kwoty pieniędzy, jaką instytucja wypłaca za przebyta mile wtedy, 
gdy pracownik używa prywatnego samochodu w sprawach służbowych. Podobnie 
do zdarzenie 

OnCalcFields

 można by wbudować prowizję, którą firma płaci 

zwykle swym handlowcom. Możliwości są tu nieograniczone. Ważną rzeczą, 
o której  należy przy tym pamiętać, jest konieczność maksymalnego ograniczania 

background image

 Rozdział 21 Reguły logiki aplikacji w aplikacjach Delphi 

637

 

ilości obliczeń, aby aplikacji nie spowolnić więcej, niż jest to bezwzględnie 
konieczne. 

OnValidate 

Inna droga do ustanowienia reguł logiki aplikacji w 

TField

 wiedzie poprzez 

zdarzenie 

OnValidate

. Każdy 

TField

 ma związane ze sobą zdarzenie 

OnValidate

, którego można użyć do weryfikacji jego wartości. Kod, który się 

w nim znajdzie, może zrobić praktycznie wszystko - może porównać wartości, jaka 
pole otrzymuje, ze stałymi, innymi polami lub rezultatami zapytania. Jeśli 
stwierdzimy,  że wartość, którą pole otrzymuje, jest nieprawidłowa, po prostu 
generujemy wyjątek. Powoduje to wyświetlenie komunikatu o 

błędzie 

i uniemożliwia zatwierdzenie wiersza. Możemy tworzyć nasze własne, pochodne 
typy wyjątków lub korzystać tylko z tych, których dostarcza Delphi.  

OnExit 

Innym powszechnie wykorzystywanym miejscem implementowania bazujących na 
polach reguł logiki aplikacji jest zdarzenie 

OnExit

  w skojarzonych  z danymi 

(data-aware) komponentach, takich jak 

DBEdit

. Do zdarzenie 

OnExit

 możemy 

dołączyć kod, który będzie się wykonywać w momencie, gdy użytkownik zacznie 
wychodzić z danej kontrolki. Kod ten może przypisywać wartości innym polom 
(na przykład, przypisywać datę zakończenia w oparciu o dostarczoną datę 
rozpoczęcia), dokonywać sprawdzenia wartości lub też uwidaczniać albo ukrywać 
inne komponenty na formularzu w zależności od wprowadzonych wcześniej 
wartości 

Zbiory danych a reguły logiki aplikacji 

Następnym poziomem, na którym konstruować można reguły logiki aplikacji 
aplikacji, jest poziom zbiorów danych (DataSet). W 

klasie komponentów 

DataSet

 (której pochodnymi są wszystkie komponenty 

Table

Query

 

StoredProc

) występują trzy zdarzenia, które zasługują na specjalną uwagę: 

OnNewRecord

BeforeDelete

 i 

BeforePost

. Odpowiadają one z grubsza 

procedurom zdarzeń 

INSERT

DELETE

 I 

UPDATE

, które można podłączać do 

tabel bazy danych.  

OnNewRecord 

Zdarzenie 

OnNewRecord

 zachodzi za każdym razem, gdy do tabeli dodawany 

jest nowy rekord. Można go wykorzystać do nadawania wartości kolumnom tabeli. 
A oto próbka kodu, dostarczająca domyślnych wartości kolumnom 

PetDeposit

 

LawnService

 z tabeli LEASE, wykorzystywanej w sekcji „Tutorial” książki: 

background image

638 

Część IV 

procedure TForm1.taLEASENewRecord(DataSet: TDataSet); 
begin 
 taLEASEPetDeposit.Value:=0; 
 taLEASELawnService.Value:=True; 
end; 

BeforeDelete 

Zdarzenie 

BeforeDelete

, jak sama nazwa wskazuje, poprzedza kasowanie 

wiersza. Zdarzenia 

BeforeDelete

 można użyć do sprawdzenia poprawności 

usuwania wiersza zanim zostanie ono wykonane. Na przykład można je 
wykorzystać aby zapobiec usunięciu wiersza, który jest powiązany z wierszami 
innej tabeli. Jeśli w trakcie obsługi tego zdarzenia wygenerujemy wyjątek, 
usuwanie zostaje przerwane. Poniżej podajemy próbkę kodu używającego tabel 
LEASE i PROPERTY z części drugiej tej książki: 

taLEASE.IndexName:=‘Propery_Number’; 

If taLEASE.FindKey([taPROPERTYProperty_Number.AsInteger]) then 

  raise EDatabaseError.Create(‘Property_Number is in use - delete 
failed’); 

Ten fragment programu zabezpiecza przed usunięciem wierszy tabeli PROPERTY 
które posiadają odwołanie do wierszy w tabeli LEASE. 

BeforePost 

Zdarzenie 

BeforePost

, jak sama nazwa wskazuje, zachodzi tuż przed 

zapisaniem wiersza w jego rodzimej tabeli. Zdarzenia 

BeforePost

 można użyć 

do sprawdzenia poprawności wartości w nowym wierszu lub zmian dokonanych 
w wierszu  istniejącym. Jeśli w trakcie obsługi tego zdarzenia wygenerujemy 
wyjątek, zatwierdzanie zostaje przerwane. Poniżej podajemy próbkę kodu 
zapewniającą,  że chronologicznie data 

LeaseEndDate

 wypadnie zawsze po 

dacie 

LeaseBeginDate

procedure TForm1.taLEASEBeforePost(DataSet: TDataSet); 
begin 
 

If (taLEASELeaseBeginDate.AsDateTime >  

 

 taLEASELeaseEndDate.AsDateTime) then 

 

 

raise EDatabaseError.Create(‘Lease ending date m. 

 

 

 ust come after its beginning date’); 

end; 

Istnieje kilka innych specjalnych zdarzeń DataSet, które można wykorzystać do 
implementowania bazujących na programie reguł logiki aplikacji. Tabela 21.1 

background image

 Rozdział 21 Reguły logiki aplikacji w aplikacjach Delphi 

639

 

zawiera listę zdarzeń dostępnych w klasie komponentów 

DataSet

, które mają 

związek z projektowaniem reguł logiki aplikacji. 

Tabela 21.2. Metody DataSet, które mogą się przydać przy implementowaniu 

bazujących na aplikacji reguł biznesowych. 

Zdarzenie Czynnik 

wywołujący 

AfterCancel

 

Zachodzi po Cancel 

AfterClose

 

Zachodzi po zamknięciu DataSet 

AfterDelete 

Zachodzi po Delete 

AfterEdit 

Zachodzi po Edit 

AfterInsert 

Zachodzi po Insert lub Append 

AfterOpen 

Zachodzi po otwarciu DataSet 

AfterPost 

Zachodzi po Post 

BeforeCancel 

Zachodzi przed Cancel 

BeforeClose 

Zachodzi przed zamknięciem DataSet 

BeforeEdit 

Zachodzi przed Edit 

BeforeInsert 

Zachodzi przed Insert lub Append 

BeforeOpen 

Zachodzi przed otwarciem DataSet 

OnCalcField 

Zachodzi gdy pole obliczane potrzebuje wartości 

OnDeleteError 

Zachodzi gdy przy kasowaniu rekordu pojawia się 
problem 

OnEditError 

Zachodzi gdy przy redagowaniu rekordu pojawia się 
problem 

OnFilterRecord 

Zachodzi gdy filtrowanie jest uaktywnione i DataSet 
potrzebuje wiersza