Více vrstvová aplikace Klient/server je rozložena do logických
jednotek, které jsou spuštěny společně na samostatných počítačích. Více
vrstvové aplikace sdílejí data a komunikují s jinými, prostřednictvím lokální
sítě nebo prostřednictvím Internetu. To poskytuje mnoho výhod,
jako je centralizovaná logika řízení a aplikace tenkého klienta.
Ve své nejjednodušší formě, někdy nazývané třívrstvový
model, více vrstvová aplikace je rozbělena na:
-
Klientskou aplikaci: poskytuje uživatelské rozhraní
na počítači uživatele.
-
Aplikační server: sídlí v centru sítě a je dostupný
pro všechny klienty a poskytuje obecné datové služby.
-
Vzdálený databázový server: poskytuje systém správy
relační databáze.
V tomto třívrstvovém modelu aplikační server spravuje tok
dat mezi klientem a vzdáleným databázovým serverem a někdy jej nazýváme
Datový
agent. Pomocí C++ Builderu obvykle vytváříme pouze aplikační server
a jeho klienty, i když by bylo také možno vytvořit vlastní databázi.
Ve složitějších více vrstvových aplikacích, další služby
sídlí mezi klientem a vzdáleným databázovým serverem. Např. zde mohou být
bezpečnostní služby agenta k zajištění bezpečnosti Internetovských transakcí
nebo most ke zpracování sdílených dat na databázových platformách, které
nejsou přímo podporované C++ Builderem.
C++ Builder podporuje více vrstvové aplikace založené
na MIDAS (Multi-tier Distributed Application Services Suite). V části Seznámení
s technologií MIDAS je poskytnut úvod do této technologie a je zde
popsána architektura třívrstvových aplikací používající MIDAS. Když již
pochopíme jak vytvářet a spravovat třívrstvové aplikace, pak můžeme vytvářet
a přidávat další služební vrstvy podle potřeby.
Po pochopení základů technologie přejdeme do části Budování
více vrstvových aplikací, kde se seznámíme podrobněji s vytvářením
více vrstvových aplikací.
Architektura MIDAS může být kombinovaná s podporou C++
Builderu pro budování ovladačů ActiveX k distribuování
klientských aplikací jako ovladačů ActiveX.
Výhody více vrstvového
modelu databáze
Model více vrstvové databázové aplikace rozděluje databázovou
aplikaci do logických částí. Klientská aplikace se zaměřuje na zobrazování
dat a interakci s uživatelem. V ideálním případě nemusí znát nic o uložení
dat a jejich údržbě. Aplikační server (střední vrstva) koordinuje a zpracovává
požadavky a aktualizace od více klientů. Zpracovává všechny detaily datových
množin a interakci se vzdáleným databázovým serverem.
Výhody více vrstvového modelu zahrnují:
-
Zaobalení logiky aplikace do sdílené střední vrstvy.
Různé klientské aplikace vždy přistupují ke stejné střední vrstvě. To umožňuje
zabránit redundanci (a udržovacím nákladům) duplikováním našich obchodních
pravidel pro každou oddělenou klientskou aplikaci.
-
Aplikace tenkého klienta. Naše klientská aplikace
může být zapsána tak, aby byla co nejmenší, delegováním většiny zpracování
do střední vrstvy. Klientské aplikace jsou potom nejen menší, ale také
se snadněji šíří, protože není zapotřebí složité instalování, konfigurování
a udržování programů pro připojení k databázi (např. BDE).
-
Distribuované zpracování dat. Distribucí práce aplikace
na několik počítačů může zvýšit výkonnost, protože vyrovnává zatížení a
umožňuje používat nadbytečné systémy, když server přestane pracovat.
-
Zvyšování bezpečnosti. Můžeme izolovat citlivou funkčnost
do vrstev, která mají různá přístupová omezení. To poskytuje flexibilní
a konfigurovatelné úrovně bezpečnosti. Střední vrstva může omezit vstupní
body k citlivému materiálu a usnadňuje řízení přístupu. Pokud používáme
MTS, pak můžeme převzít výhody bezpečnostního modelu, který podporuje.
Seznámení s technologií MIDAS
MIDAS poskytuje mechanismus, kterým klientská aplikace a
aplikační server komunikují s databázovými informacemi. Použití MIDAS požaduje
DBCLIENT.DLL, používanou klientskou i serverovou aplikací pro správu datových
množin uložených jako datové pakety. MIDAS také zahrnuje Průzkumník SQL
pro pomoc v administraci databáze a k importu serverových omezení do Datového
slovníku a tak mohou být testovány na libovolné úrovni více vrstvové aplikace.
Můžeme také požadovat použití OLEnterprise, což poskytuje služby založené
na COM (Business Object Broker), pro transparentnost umístění a balancování
zavádění.
Více vrstvová aplikace založená na MIDAS používá komponenty
ze stránky MIDAS Palety komponent, plus vzdálené datové moduly, které vytvoříme
průvodcem na stránce Multitier dialogového okna New Items.
Tyto komponenty jsou popsány v následující tabulce:
Komponenta |
Popis |
vzdálené datové moduly |
Specializované datové moduly, které pracují se Serverem
automatizace COM pro zpřístupnění libovolného poskytovatele, který obsahuje
klientskou aplikaci. Používáno na aplikačním serveru. |
komponenta poskytovatele |
Datový agent, který poskytuje data vytvářením datových
paketů a řešící aktualizace klienta. Tyto služby jsou prováděny prostřednictvím
rozhraní
IProvider. Používáno na aplikačním serveru. |
komponenta klientské datové množiny |
Specializovaná datová množina používající DBCLIENT.DLL
místo BDE pro správu dat uložených v datových paketech. |
komponenty připojení |
Rodina komponent, které sídlí na serveru a dělá rozhraní
IProvider
dostupným z klientských datových množin. Každá komponenta připojení je
specializovaná k použití jistého komunikačního protokolu. |
Více informací jak tyto komponenty použít k vytvoření
více vrstvové aplikace najdeme v bodech:
Úvod do více
vrstvových aplikací založených na MIDAS
Následující očíslované kroky ukazují normální sekvenci činností
pro více vrstvové aplikace založené na MIDAS:
-
Uživatel spustí klientskou aplikaci. Klient se připojí k
aplikačnímu serveru (který může být specifikován při návrhu nebo za běhu).
Pokud aplikační server ještě není spuštěn, pak je spuštěn. Klient získá
rozhraní poskytovatele od aplikačního serveru.
-
Klient požaduje data od aplikačního serveru. Klient může
požadovat všechna data najednou, nebo je může požadovat po malých částech
prostřednictvím sezení.
-
Aplikační server získá data (nejprve v případě nutnosti zřídí
databázové připojení), balí je pro klienta a vrací datový paket klientovi.
Další data (např. datová omezení požadovaná databází) mohou být vložena
do metadat datového paketu. Tento proces balení dat do datových paketů
se nazývá poskytování.
-
Klient dekóduje datový paket a zobrazí data uživateli.
-
Jak uživatel pracuje s klientskou aplikací, data jsou aktualizována
(záznamy jsou přidávány, rušeny nebo modifikovány). Tyto modifikace jsou
ukládány v deníku změn klienta.
-
Klient může aplikovat své aktualizace na aplikační server,
obvykle v reakci na akci uživatele. Pro aplikování aktualizací, klient
zabalí svůj deník změn a zašle jej jako datový paket na server.
-
Aplikační server dekóduje balíček a odešle aktualizace v
kontextu transakce. Pokud záznam nemůže být odeslán na server (např. protože
jiná aplikace změnila záznam po jeho předání klientovi a před aplikováním
jeho změn), pak aplikační server se pokusí "smířit" změny klienta se současnými
daty nebo tento záznam odložit. Proces odesílání záznamů a odkládání problémových
záznamů se nazývá řešení.
-
Když aplikace dokončí proces řešení, vrátí nevyřešené záznamy
klientovi pro další řešení.
-
Klient se pokusí vyřešit zbývající problémy. Je mnoho způsobů
jak to klient může provést. Obvykle klient se pokusí opravit situaci a
zabránit zrušení změn. Pokud chyby jsou opraveny, pak klient je aplikuje
znova.
-
Klient obnovuje svá data ze serveru.
Struktura klientské aplikace
Z hlediska koncového uživatele, klientská aplikace více vrstvové
aplikace vypadá a chová se jinak než tradiční dvouvrstvová aplikace. Strukturálně
klientská aplikace vypadá jako jednovrstvová aplikace plochých souborů.
Interakce uživatele probíhá prostřednictvím datových ovladačů, které zobrazují
data z komponenty klientské datové množiny.
Na rozdíl od aplikací plochých souborů, klientská datová
množina ve více vrstvových aplikacích získává svoje data prostřednictvím
rozhraní na aplikačním serveru. Toto rozhraní také používá k odesílání
aktualizací na aplikační server. Ve většině případů je to rozhraní
IProvider.
Klient získá toto rozhraní od komponenty připojení.
Poznámka: Když používáme MTS, pak můžeme zvolit
nepoužívání rozhraní IProvider našimi klientskými datovými množinami.
Zápisem kódu k poskytnutí dat do a k aplikování aktualizací z klientské
datové množiny bez použití rozhraní IProvider, naše MTS aplikace
může převzít výhody služeb MTS jako jsou transakce MTS a aktivace "just-in-time".
Více informací nalezneme v Používání MTS.
Komponenta připojení zřizuje připojení k aplikačnímu
serveru. Pro používání různých komunikačních protokolů jsou dostupné různé
komponenty připojení. Přehled komponent připojení je uveden v následující
tabulce:
Komponenta |
Protokol |
TDCOMConnection |
DCOM |
TSocketConnection |
Sokety Windows (TCP/IP) |
TOLEnterpriseConnection |
OLEnterprise (RPCs) |
Poznámka: Další dvě komponenty připojení TRemoteServer
a TMIDASConnection jsou poskytnuty pro zpětnou kompatibilitu.
Když propojení je zřízeno, pak komponenta propojení použije
rozhraní
IDataBroker
aplikačního serveru k získání rozhraní IProvider pro libovolnou
datovou množinu ve vzdáleném datovém modulu.
Struktura aplikačního serveru
Aplikační server obsahuje speciální třídy odvozené od rozhraní
IDataBroker,
které klientské aplikace používají k získání přístupu k poskytovateli dat.
Pokud vytváříme aplikační server jako Active Library (DLL), která
je instalovaná s MTS, pak tato speciální třída
také spravuje rozhraní IObjectContext umožňující interakci s MTS
proxy.
Mimo třídy, která podporuje rozhraní IDataBroker,
aplikační server obsahuje vzdálené datové moduly, které obvykle obsahují
komponentu poskytovatele k udělání každé datové množiny aplikačního serveru
dostupné v klientské aplikaci. Rozhraní IProvider tedy může:
-
Přijímat datové požadavky od klienta, získávat požadovaná
data od databázového serveru, balit data pro transakce a zasílat data klientské
datové množině. Tato aktivita se nazývá poskytování.
-
Přijímat aktualizovaná data od klientské datové množiny,
aplikovat aktualizace do databáze, zaznamenávat neaplikovatelné aktualizace,
vracet nevyřešené aktualizace klientovi k následujícímu vyřešení. Tato
aktivita se nazývá
řešení.
Poznámka: Pokud do aplikačního serveru nedodáme
komponentu poskytovatele pro datové množiny podporující BDE, pak jedna
je pro nás vytvořena dynamicky. Explicitním přidáním komponenty poskytovatele
získáme větší řízení a umožníme poskytování z dalších typů datových množin.
Často poskytovatel používá datové množiny podporující
BDE, které nalezneme ve dvouvrstvových aplikacích podporujících BDE. Můžeme
přidat komponenty databáze a sezení podle potřeby, a to stejně jako ve
dvouvrstvových aplikacích založených na BDE.
Pokud aplikační server podporuje MTS, pak vzdálený datový
modul obsluhuje události, pro které aplikační server je aktivován nebo
deaktivován. To umožňuje aplikačnímu serveru zřídit databázové připojení
při aktivování a jeho uvolnění při deaktivování.
Používání MTS
Používání MTS umožňuje našim aplikačním serverům přebírat
výhody:
-
Bezpečnosti MTS. MTS poskytuje bezpečnost založenou
na rolích pro náš aplikační server. Klientům jsou přiřazeny role, které
určují jak mohou přistupovat k rozhraní aplikačního serveru. Použijeme
rozhraní IObjectContext, které je udržováno aplikačním serverem
pro přístup ke službám bezpečnosti MTS.
-
Udržování databázového připojení. Datové moduly MTS
automaticky udržují databázové připojení a tak, když jeden klient dokončí
databázové připojení, jiný klient jej může opětovně použít. To snižuje
síťový provoz, protože naše střední vrstva se nemusí odhlašovat a opětovně
přihlašovat ke vzdálenému databázovému serveru. Při udržování databázového
připojení, naše komponenta databáze musí mít nastavenu vlastnost KeepConnection
na false aby aplikace mohla maximalizovat sdílení připojení.
-
Transakce MTS. Když používáme MTS, pak můžeme integrovat
své vlastní transakce MTS do aplikačního serveru k poskytnutí rozšířené
podpory transakcí. Transakce MTS se mohou rozšířit na více databází nebo
vkládat funkce, které všechny databáze neumožňují.
-
Aktivace just-in-time a deaktivace as-needed-as-possible.
Můžeme zapsat svůj server MTS jehož instance jsou aktivovány a deaktivovány
podle potřeby. Když použijeme aktivaci just-in-time a deaktivaci as-soon-as-possible,
pak náš aplikační server je instantizován pouze když je zapotřebí ke zpracování
klientských požadavků.
Tato aktivace a deaktivace tvoří kompromis mezi přihlašováním
všech klientů prostřednictvím jedné instance vzdáleného modulu dat a vytvářením
oddělených instancí pro každé klientské připojení. S jednou instancí vzdáleného
modulu dat, aplikační server musí obsloužit všechna databázová volání prostřednictvím
jednoho databázového připojení. To tvoří úzký profil a při mnoha klientech
to může snižovat výkonnost. S více instancemi vzdálených datových modulů,
každá instance může udržovat samostatné databázové připojení a tedy není
zapotřebí databázový přístup serializovat. Toto ale monopolizuje zdroje,
protože ostatní klienti nemohou používat databázové připojení, které je
přiřazené ke vzdálenému datovému modulu jiného klienta.
K převzetí výhod transakcí, aktivace just-in-time a deaktivace
as-soon-as-possible, instance vzdálených datových modulů musí být beze
stavové. Protože rozhraní
IProvider se opírá o stavové informace,
klient nemůže použít rozhraní
IProvider pokud chceme převzít
výhody těchto služeb. Musíme vytvořit vlastní rozhraní pro poskytování
dat a aplikování aktualizací.
Varování: Když používáme MTS, databázové připojení
nemůže být otevřeno pokud vzdálený datový modul je aktivován. V průběhu
vývoje naší aplikace, se musíme ujistit, že všechny datové množiny nejsou
aktivní a databáze nejsou připojena před spuštěním naší aplikace. V aplikaci
samotné, musí být kód pro otevření databázového připojení při aktivování
datového modulu a k uzavření, když datový modul je deaktivován.
Používání rozhraní IDataBroker
Aplikační server podporuje rozhraní IDataBroker. Komponenty
připojení v klientské aplikaci používají toho rozhraní k formování připojení.
IDataBroker definuje pouze jednu metodu: GetProviderNames.
Komponenty připojení volají GetProviderNames k získání seznamu komponent
poskytovatelů na aplikačním serveru. Klientské datové množiny se připojují
k poskytovateli z tohoto seznamu, nastavením jejich vlastnosti ProviderName
na jedno z těchto jmen.
Poznámka: Když klient použije GetProviderNames
pro připojení klientské datové množiny k poskytovateli na aplikačním serveru,
pak stav svého vzdáleného datového modulu musí být chráněn tak dlouho,
dokud klient drží odkaz na rozhraní poskytovatele.
Používání rozhraní IProvider
Rozhraní IProvider je implementováno komponentou poskytovatele
na aplikačním serveru. Klientské datové množiny v klientské aplikaci používají
rozhraní
IProvider ke komunikaci s touto komponentou poskytovatele.
Většina klientských aplikací nepoužívá rozhraní IProvider přímo,
ale je vyvoláváno nepřímo prostřednictvím vlastností a metod klientské
datové množiny. Nicméně, když je to zapotřebí, můžeme přímo volat rozhraní
IProvider
pomocí vlastnosti
Provider klientské datové množiny.
Následující tabulka uvádí vlastnosti a metody rozhraní
IProvider,
odpovídající vlastnosti a metody v TProvider, které je implementují
a odpovídající vlastnosti a metody v TClientDataSet, které je používá.
IProvider |
TProvider |
TClientDataSet |
Metoda ApplyUpdates |
Metoda ApplyUpdates |
Použito metodou ApplyUpdates |
Vlastnost Constraints |
Vlastnost Constraints |
Aplikace musí použít rozhraní přímo |
Vlastnost Data |
Vlastnost Data |
Vlastnost Data |
Metoda DataRequest |
Metoda DataRequest |
Aplikace musí použít rozhraní přímo |
Metoda Get_Constraints |
Vlastnost Constraints |
Aplikace musí použít rozhraní přímo |
Metoda Get_Data |
Metoda Get_Data |
Použito k implementaci vlastnosti Data |
Metoda GetMetaData |
Metoda GetRecords (Count = 0) |
Použito interně |
Metoda GetRecords |
Metoda GetRecords |
Použito metodou GetNextPacket |
Metoda Reset |
Metoda Reset |
Použito interně |
Metoda Set_Constraints |
Vlastnost Constraints |
Aplikace musí použít rozhraní přímo |
Metoda SetParams |
Metoda SetParams |
Použito pro vlastnost Params |
Poznámka: Všechny vlastnosti a mnoho metod rozhraní
IProvider
působí na informace o stavu ve vzdáleném datovém modulu. Z tohoto důvodu
nelze použít toto rozhraní pro aplikace, které používají MTS.
Volba protokolu připojení
Každý komunikační protokol, který můžeme použít pro připojení
naší klientské aplikace k aplikačnímu serveru poskytuje své vlastní unikátní
výhody. Před volbou protokolu musíme zvážit kolik klientů můžeme očekávat,
jak budeme šířit naši aplikaci a budoucí plány vývoje.
Následující body popisují unikátní služby každého komunikačního
protokolu:
Používání připojení DCOM
DCOM poskytuje nejpřímější možnosti komunikace, nevyžadující
další běžící aplikace na serveru. Nicméně, protože DCOM není obsaženo ve
Windows 95, klientské počítače nemusí mít DCOM instalováno.
DCOM poskytuje pouze možnosti, které umožňují používat
bezpečnostní služby MTS. Bezpečnost MTS je založena na přiřazení rolí k
volajícím objektům MTS. Když voláme do MTS pomocí DCOM, pak DCOM informuje
MTS o klientské aplikaci, která generuje volání. MTS pak může aktuálně
určit roli volajícího. Volání DCOM do aplikačního serveru jsou v zájmu
klienta.
Používání připojení Socket
Sokety TCP/IP umožňují vytvořit tenkého klienta. Např. pokud
distribuujeme naší klientskou aplikaci prostřednictvím Web jako aktivní
formulář, pak si nemůžeme být jisti zda klientský systém podporuje DCOM.
Sokety poskytují nejnižší obecný protokol o kterém víme, že je dostupný
pro připojení k aplikačnímu serveru.
Místo instantizace vzdáleného datového modulu přímo od
klienta (což nastává s DCOM), sokety používají oddělenou aplikaci na serveru
(ScktSrver.exe nebo ScktSrvc.exe), která akceptuje klientské
požadavky a instantizuje vzdálený datový modul pomocí COM. Komponenta připojení
na klientu a ScktSrvr.exe nebo ScktSrvc.exe na serveru jsou
zodpovědné za řazení volání IProvider.
Když používáme sokety, pak není ochrana na serveru před
chybami klientského systému před uvolněním odkazu na rozhraní na aplikačním
serveru. Je to v důsledku menších provozních zpráv než při použití DCOM
(kde jsou periodicky zasílány udržovací zprávy), a může to způsobit neuvolnění
zdrojů na aplikačním serveru, neboť server nezjistí, že klient zdroje již
nepotřebuje.
Používání OLEnterprise
OLEnterprise používá Business Object Broker namísto
spoléhání se na klientskou stranu. Bussines Object Broker poskytuje
vyvážené zavádění a transparentnost umístění.
Když používáme OLEnterprise, pak musíme nainstalovat
jeho běhové prostředí a to na klientském i serverovém systému. OLEnterprise
seřadí volání Automation a komunikace mezi klientským a serverovým systémem
pomocí volání vzdálených procedur (RPC). Více informací najdete v dokumentaci
OLEnterprise.
Budování více vrstvových
aplikací
Obecné kroky pro vytváření více vrstvových aplikací jsou:
-
Vytvoříme aplikační
server.
-
Registrujeme nebo instalujeme aplikační server.
-
Pokud aplikační server používá jako komunikační protokol
DCOM, sokety nebo OLEnterprise, pak se chová jako server automatizace a
musí být registrován jako libovolný jiný server ActiveX nebo COM.
-
Pokud používáme MTS, pak aplikační server musí být Active
Library místo EXE. Protože všechna volání COM musí projít přes proxy MTS,
aplikační server nemusíme registrovat. Můžeme jej nainstalovat s MTS.
-
Vytvoříme klientskou
aplikaci.
Pořadí vytváření je důležité. Musíme vytvořit a spustit aplikační
server před vytvářením klienta. Při návrhu se budeme potřebovat připojit
k aplikačnímu serveru pro testování našeho klienta. Můžeme ovšem vytvořit
klienta bez specifikace aplikačního serveru při návrhu a za běhu pouze
předat jméno serveru. Nicméně, pokud chceme vidět, zda naše aplikace pracuje
jak očekáváme při kódování během návrhu, je vhodné zvolit server a poskytovatele
pomocí Inspektora objektů.
Poznámka: Pokud nevytváříme klientskou aplikaci
na stejném počítači jako je server a nepoužíváme připojení sokety, pak
můžeme registrovat nebo instalovat aplikační server na systému klienta.
Tím uděláme aplikační server dostupným při návrhu z komponenty připojení
tak, že zvolíme jméno serveru a poskytovatele z rozbalovacího seznamu v
Inspektoru objektů. Pokud používáme propojení sokety, pak komponenta připojení
získá jména registrovaných serverů z počítače serveru.
Následující body popisují jak můžeme rozšířit základ
více vrstvové architektury k podpoře speciálních požadavků naší aplikace:
Vytváření aplikačního serveru
Aplikační server vytváříme podobně jako většinu databázových
aplikací. Hlavním rozdílem je to, že aplikační server obsahuje nějaký typ
poskytovatele. Můžeme použít komponentu TProvider nebo TDataSetProvider
nebo vlastnost Provider potomka TDBDataSet (např. TTable).
K vytvoření aplikačního serveru zahájíme nový projekt,
uložíme jej a provedeme tyto kroky:
-
Přidáme k projektu nový vzdálený datový modul. Zvolíme File
| New, přejdeme na stránku Multitier a zvolíme
-
Remote Data Module, pokud vytváříme server Automatizace
COM, který klienti budou používat pomocí DCOM, soketů nebo OLEnterprise.
-
MTS Data Module, pokud vytváříme Active Library,
kterou klienti zpřístupňují použitím MTS. Připojení může být formováno
pomocí DCOM, soketů nebo OLEnterprose.
Více informací o nastavování vzdáleného datového modulu nalezneme
v Nastavování vzdáleného
datového modulu.
Poznámka: Když k našemu projektu přidáme vzdálený
datový modul, pak Průvodce vytvoří také speciální objekt Automatizace COM,
který obsahuje odkaz na vzdálený datový modul a používáme jej k hledání
poskytovatele.
-
Umístíme potřebné komponenty tabulek, dotazů a uložených
procedur na datový modul a nastavíme na nich přístup na databázový server.
-
Umístíme komponentu poskytovatele nebo datové množiny podporující
BDE na datový modul pro přístup ke každé datové množině. Musíme explicitně
exportovat každého poskytovatele v datovém modulu tím, že jej registrujeme
v knihovně typů. Provedeme to tak, že vybereme postupně každou komponentu
poskytovatele (TProvider, TDataSetProvider nebo TBDEDataSet)
a v místní nabídce datového modulu zvolíme Export From <Name>.
-
Pokud používáme komponentu poskytovatele, nastavíme její
vlastnost DataSet na jméno zpřístupňované datové množiny. Pro poskytovatele
můžeme nastavit další vlastnosti. Více informací o nastavování poskytovatele
nalezneme ve Vytváření
poskytovatele dat pro aplikační server.
-
Zapíšeme kód aplikačního serveru k implementaci událostí,
sdílených obchodních pravidel a sdílené bezpečnosti. Můžeme chtít rozšířit
rozhraní aplikačního serveru k poskytnutí dalších způsobů volání serveru
klientskou aplikací.
-
Uložíme, přeložíme a registrujeme nebo instalujeme aplikační
server.
-
Když aplikační server používá jako komunikační protokol DCOM,
sokety nebo OLEnterprise, pak pracuje jako server Automatizace a musí být
registrovaný podobně jako jiný server ActiveX nebo COM.
-
Pokud používáme MTX, pak aplikační server musí být Active
Library místo EXE. Protože všechna volání COM musí procházet přes proxi
MTS, není nutno aplikační server registrovat.
-
Pokud naše serverová aplikace nepoužívá DCOM, pak musíme
instalovat software který přijímá klientské zprávy, instantizuje vzdálené
datové moduly a řadí volání rozhraní. Pro sokety TCP/IP je to aplikace
vyřizující sokety. C++ Builder je dodáván se dvěmi vyřizujícími aplikacemi:
ScktSrvr.exe,
jednoduchou na soketech založenou aplikací, kterou můžeme spustit na libovolném
systému a ScktSrvc.exe, které je aplikací služby NT. Pro OLEnterprise
je to běhové prostředí OLEnterprise.
Nastavování vzdáleného
datového modulu
Když nastavujeme a spouštíme aplikační server, pak nezřizujeme
žádné propojení s klientskou aplikací. K zřízení připojení na aplikační
server klientská aplikace používá své komponenty připojení a obvykle je
zřízeno jedno připojení k výběru poskytovatele. Vše to proběhne automaticky,
bez nutnosti zapisovat kód pro správu odcházejících požadavků nebo předávání
rozhraní.
Po zřízení připojení, rozhraní mezi aplikačním serverem
a klientskou datovou množinou je automatické a transparentní pro vývojáře
i uživatele. Připojení je udržováno klientskou aplikací.
Když vytváříme vzdálený datový modul, pak musíme poskytnout
jisté informace, které indikují jak reagovat na klientské požadavky. Tyto
informace se liší podle toho, zda používáme nebo nepoužíváme pro přístup
na náš aplikační server, MTS. Následující body popisují jak konfigurovat
vzdálený datový modul:
Konfigurování vzdáleného
datového modulu nepoužívajícího MTS
K přidání vzdáleného datového modulu bez poskytnutí podpory
MTS, zvolíme
File | New a na stránce Multitier vybereme Remote
Data Module. Tím spustíme průvodce vytvářením vzdáleného datového modulu.
Musíme dodat jméno třídy pro náš vzdálený datový modul.
Je to základní jméno potomka TDataModule, kterého naše aplikace
vytváří. Je také základním jménem rozhraní serverové aplikace. Např. pokud
specifikujeme jméno třídy MyDataServer, pak průvodce vytvoří novou
jednotku deklarující
TMyDataServer, jako potomka TDataModule.
V hlavičkovém souboru, Průvodce také deklaruje speciální implementační
třídu (TMyDataServerImpl), potomka TDataBroker, která implementuje
TMyDataServer.
Poznámka: Můžeme přidat své vlastní vlastnosti
a metody k novému rozhraní. Více informací nalezneme v Rozšiřování
rozhraní aplikačního serveru.
Pokud vytváříme DLL (Active Library), pak musíme
v Průvodci vytvářením vzdáleného datového modulu specifikovat vláknový
model. Můžeme volit z: Single-threaded, Apartment-threaded,
Free-threaded
nebo Both.
-
Pokud zvolíme Single-threaded, pak COM zajišťuje,
že je vždy obsluhován pouze jeden klientský požadavek. Není nutno se zabývat
působením jednoho klientského požadavku na jiný klientský požadavek.
-
Když zvolíme Apartment-threaded, pak COM zajišťuje,
že každá instance našeho vzdáleného modulu obsluhuje jeden požadavek. Když
zapisujeme kód do knihovny Apartment-threaded, pak musíme zajistit,
že nenastane konflikt vláken, pokud používáme globální proměnné nebo objekty
neobsažené ve vzdáleném datovém modulu.
-
Při volbě Free-threaded, naše aplikace může získávat
souběžné klientské požadavky na několika vláknech. Jsme odpovědni za zajištění
vláknově bezpečné aplikace. Protože více klientů může přistupovat k našemu
vzdálenému datovému modulu současně, musíme chránit naše instance dat (vlastnosti,
obsažené objekty apod.) stejně jako globální proměnné. Tento model není
doporučován, protože nemá zabudovanou podporu vláken pro rozhraní IProvider.
-
Když zvolíme Both, pak naše knihovna pracuje stejně
jako při volbě
Free-threaded, s jedinou výjimkou: všechna zpětná
volání (volání do rozhraní klienta) jsou pro nás serializována.
Konfigurování vzdáleného
datového modulu používajícího MTS
K přidání vzdáleného datového modulu k naší aplikaci, když
používáme MTS, zvolíme File | New a na stránce Multitier
vybereme MTS Data Module. Tím spustíme Průvodce vytvářením datového
modulu MTS.
Musíme předat jméno třídy pro náš vzdálený datový modul.
Je to základní jméno potomka TDataModule, kterého naše aplikace
vytváří. Je také základním jménem rozhraní serverové aplikace. Např. pokud
specifikujeme jméno třídy MyDataServer, pak průvodce vytvoří novou
jednotku deklarující
TMyDataServer, jako potomka TDataModule.
V hlavičkovém souboru, Průvodce také deklaruje speciální implementační
třídu (TMyDataServerImpl), potomka TDataBroker, která implementuje
TMyDataServer.
TMyDataServerImpl
obsahuje datové položky pro rozhraní IObjectContext, které můžeme
použít pro správu transakcí MTS, testování bezpečnosti MTS apod.
Poznámka: Můžeme přidat své vlastní vlastnosti
a metody k novému rozhraní. Musíme to udělat když chceme převzít výhody
transakcí MTS nebo aktivace just-in-time. Více informací nalezneme v Rozšiřování
rozhraní aplikačního serveru.
MTS aplikace jsou vždy DLL (Active Libraries).
V Průvodci vytvářením datového modulu MTS musíme specifikovat vláknový
model. Můžeme volit: Single,
Apartment nebo Both:
-
Pokud zvolíme Single, pak MTS zajistí, že najednou
může být obsluhován pouze jediný klientský požadavek. Zde nemohou vznikat
problémy s interferencí klientských požadavků.
-
Když zvolíme Apartment, pak MTS zajišťuje, že každá
instance vzdáleného datového modulu obsluhuje jeden požadavek, ale toto
volání nepoužívá vždy stejné vlákno. Nemůžeme používat proměnné vlákna,
protože není zajištěno, že následující volání instance vzdáleného datového
modulu použije stejné vlákno. Pokud používáme globální proměnné nebo objektu
neobsažené ve vzdáleném datovém modulu, pak musíme zabránit konfliktům
vláken. Místo používání globálních proměnných, můžeme používat správce
sdílených vlastností.
-
Pokud zvolíme Both, pak volání MTS do rozhraní aplikačního
serveru, probíhá stejným způsobem jako při volbě Apartment. Nicméně,
libovolná zpětná volání prováděná na klientských aplikacích jsou serializované
a tedy není zapotřebí se zabývat jejich interferencemi.
Poznámka: Model Apartment pod MTS se liší
od odpovídajícího modelu pod DCOM.
Musíme také specifikovat atributy transakcí MTS našeho
vzdáleného datového modulu. Můžeme volit z:
-
Requires a transaction. Když vybereme tuto volbu,
pak vždy když klient použije rozhraní našeho aplikačního serveru, toto
volání je provedeno v kontextu transakce MTS. Pokud volající předává transakci,
pak nová transakce nemusí být vytvořena.
-
Requires a new transaction. Když vybereme novou volbu,
pak vždy když klient použije rozhraní našeho aplikačního serveru, pak pro
toto volání je automaticky vytvořena nová transakce.
-
Supports transactions. Když vybereme tuto volbu, pak
náš aplikační server může být použit v kontextu transakce MTS ale volající
musí předat transakci, když vyvolává rozhraní.
-
Does not support transactions. Když vybereme tuto
volbu, pak náš aplikační server nemůže být použit v kontextu transakcí
MTS.
Vytváření
poskytovatele dat pro aplikační server
Každý vzdálený datový modul na aplikačním serveru obvykle
obsahuje jednu nebo více komponent poskytovatele. Komponenta poskytovatele
odpovídá rozhraní
IProvider, balí data do datových paketů, které
jsou zasílány klientovi a aplikuje aktualizace získané od klienta. Poskytovatel
pracuje ve spojení s komponentou řešitele, která zpracovává detaily řešení
konfliktů dat na databázi (nebo na datové množině).
Poznámka: Místo umisťování komponent poskytovatele
do vzdáleného datového modulu a jejich používání k zřízení rozhraní IProvider,
které můře být používáno s klientskými datovými množinami, můžeme zvolit
k použití vlastnost Provider komponenty TStoredProc, TQuery
nebo TTable k překlenutí explicitního použití samostatné komponenty
poskytovatele. Když použijeme vlastnost Provider komponenty datové
množiny přímo, pak C++ Builder vytváří a spravuje poskytovatele pro nás
za scénou.
Když použijeme komponentu poskytovatele, pak ji musíme
přiřadit ke komponentě datové množiny na aplikačním serveru. Provedeme
to nastavením vlastnosti DataSet poskytovatele na jméno používané
datové množiny. Pokud poskytujeme z a řešíte na datovou množinu, pak můžeme
použít TDataSetProvider, která pracuje s libovolným potomkem TDataSet.
Pokud řešíme přímo do databáze, pak musíme použít TProvider, umožňující
použít pouze datové množiny podporující BDE.
Při návrhu vybereme z dostupných datových množin ve vlastnosti
DataSet
v Inspektoru objektů.
Pokud vytváříme beze stavový vzdálený datový modul, pak
většina práce komponenty poskytovatele probíhá automaticky. Není zapotřebí
zapisovat žádný kód na poskytovateli k vytvoření plně funkčního aplikačního
serveru. Používání komponenty poskytovatele dává naší aplikací více řízení
nad určením jaké informace pro klienty balit a jak naše klientská aplikace
reaguje na požadavky klientů.
Následující body popisují jak používat komponentu poskytovatele
k řízení interakcí s klientskou aplikací:
Řízení jaké
informace jsou uloženy v datových paketech
Jsou tři způsoby řízení, které informace jsou vloženy do
datových paketů zasílaných ke a od klienta. Jedná se o:
Specifikování
které položky jsou v datových paketech
K řízení, které položky jsou vloženy do datových paketů,
vytvoříme trvalé položky v datové množině, kterou poskytovatel používá
k budování paketů. Poskytovatel pak vloží pouze tyto položky. Položky jejichž
hodnoty jsou generovány dynamicky na serveru (jako jsou počitatelné nebo
vyhledávací položky) mohou být vloženy, ale zobrazí se na konci klientské
datové množiny jako statické položky určené pouze pro čtení.
Pokud klientská datová množina bude editována a aktualizace
aplikovány na aplikační server, pak musíme vložit položky určující záznam
v datovém paketu. Jinak při aplikování aktualizace nemusí být možno určit,
který záznam aktualizovat. Pokud nepožadujeme aby klientská datová množina
byla schopna vidět nebo používat speciální položky poskytnuté pouze k zajištění
unikátnosti, pak nastavíme vlastnost ProviderFlags pro tyto položky
na pfHidden.
Poznámka: Vložení dalších položek k zabránění
duplikace záznamů je také předpokladem používání dotazů na aplikačním serveru.
Dotaz musí vložit další položky, aby záznamy se staly unikátními, když
naše aplikace nepoužívá všechny položky.
Nastavování
voleb ovlivňujících datové pakety
Vlastnost Options komponenty poskytovatele umožňují
specifikovat zda BLOB nebo vnořené detailní tabulky jsou zasílány, zda
jsou vloženy vlastnosti zobrazení položky, apod. Následující tabulka uvádí
možné hodnoty, které mohou být vloženy do Options.
Hodnota |
Význam |
poFetchBlobsOnDemand |
Hodnoty položek BLOB nejsou vkládány do datových paketů.
Klientská aplikace musí požadovat tyto hodnoty, když je potřebuje. Pokud
vlastnost
FetchOnDemand klientské datové množiny je true,
pak klient požaduje tyto hodnoty automaticky. Jinak, klientská datová množina
použije metodu FetchBlobs klientské datové množiny k získání dat
BLOB. |
poFetchDetailsOnDemand |
Když poskytovatel reprezentuje Master vzájemného vztahu
Master-detail, pak vnořené detailní hodnoty nejsou vloženy do datových
paketů. Klientská aplikace musí požadovat tyto hodnoty, když je potřebuje.
Pokud vlastnost
FetchOnDemand klientské datové množiny je true,
pak klient požaduje tyto hodnoty automaticky. Jinak, klientská datová množina
použije metodu FetchDetails klientské datové množiny k získání vnořených
detailů. |
poIncFieldProps |
Datový paket obsahuje následující vlastnosti položek
(jsou-li aplikovatelné):
Alignment,
DisplayLabel,
DisplayWidth,
Visible,
DisplayFormat,
EditFormat,
MaxValue,
MinValue,
Currency,
EditMask
a DisplayValues. |
poCascadeDeletes |
Když poskytovatel reprezentuje Master vzájemného vztahu
Master-detail, pak detailní záznamy jsou rušený serverem automaticky pokud
je zrušen záznam Master. K použití této volby, databázový server musí být
nastaven k provádění kaskádovitého rušení jako součást referenční integrity. |
poCascadeUpdates |
Když poskytovatel reprezentuje Master vzájemného vztahu
Master-detail, pak detailní záznamy jsou aktualizovány serverem automaticky
pokud je aktualizována odpovídající hodnota záznamu Master. K použití této
volby, databázový server musí být nastaven k provádění kaskádovité aktualizace
jako součást referenční integrity. |
poReadOnly |
Klientská datová množina nemůže aplikovat aktualizace
poskytovateli. |
Přidávání
přizpůsobených informací do datových paketů
Poskytovatel může zasílat aplikací definované informace
do datových paketů pomocí události OnGetDataSetProperties. Tyto
informace jsou kódované jako OleVariant a uloženy pod námi specifikovaným
jménem. Klientské datové množiny v klientské aplikaci mohou pak získávat
informace pomocí své metody GetOptionalParam. Můžeme také specifikovat,
že informace budou vloženy do paketů Delta, které klientská datová
množina zasílá při aktualizování záznamů. V tomto případě, klientská aplikace
se nemusí starat o informace, ale server může zasílat okružní zprávy sám
sobě.
Když přidáme přizpůsobené informace v události OnGetDataSetProperties,
pak každý atribut (někdy nazývaný nepovinný parametr) je specifikován
pomocí pole Variant, které obsahují tři prvky: jméno (řetězec), hodnota
(Variant) a logický příznak indikující zda informace bude přidávána do
paketů Delta, když klient aplikuje aktualizace. Více atributů může
být přidáno vytvořením pole variant polí variant. Např. následující obsluha
události OnGetDataSetProperties zasílá dvě hodnoty, čas poskytnutí
dat a celkový počet záznamů ve zdrojové datové množině. Pouze informace
o čase poskytnytí dat jsou vráceny když klient aplikuje aktualizace:
void __fastcallTMyDataModule1::Provider1GetDataSetProperties(TObject
*Sender,
TDataSet *DataSet, out OleVariant Properties)
{
int ArrayBounds[2];
ArrayBounds[0] = 0;
ArrayBounds[1] = 1;
Properties = VarArrayCreate(ArrayBounds,
1, varVariant);
Variant values[3];
values[0] = Variant("TimeProvided");
values[1] = Variant(Now());
values[2] = Variant(true);
Properties[0] = VarArrayOf(values,2);
values[0] = Variant("TableSize");
values[1] = Variant(DataSet->RecordCount);
values[2] = Variant(false);
Properties[1] = VarArrayOf(values,2);
}
Když klient aplikuje aktualizace, pak čas poskytnutí
původních záznamů může být přečten v události OnUpdateData poskytovatele:
void __fastcallTMyDataModule1::Provider1UpdateData(TObject
*Sender,
TClientDataSet *DataSet)
{
Variant WhenProvided = DataSet->GetOptionalParam("TimeProvided");
...
}
Reagování na datové
požadavky klienta
Ve většině více vrstvových aplikací, klientské požadavky
na data jsou zpracovány automaticky. Klientská datová množina požaduje
datové pakety voláním GetRecords (prostřednictvím rozhraní IProvider
nebo přizpůsobeného rozhraní). Poskytovatel reaguje automaticky předáním
dat z přiřazené datové množiny, vytvořením datového paketu a zasláním paketu
klientovi.
Poskytovatel má možnost editovat data po jejich sestavení
do datového paketu, ale před odesláním paketu klientovi. Např. poskytovatel
může zakódovat citlivá data před odesláním klientovi nebo z paketu odstranit
záznamy na základě nějakého kritéria (jako je role uživatele v aplikacích
MTS).
K editováni dat paketu před odesláním na klienta zapíšeme
obsluhu události
OnGetData. Datový paket je poskytnut jako parametr
ve tvaru klientské datové množiny. Metody této klientské datové množiny
použijeme k editaci dat před jejich odeslání klientovi.
Reagování na
aktualizační požadavky klienta
Poskytovatel aplikuje aktualizace do záznamů databáze na
základě datového paketu Delta získaného od klientské aplikace. Klient
požaduje aktualizování voláním metody ApplyUpdates (prostřednictvím
rozhraní IProvider nebo prostřednictvím přizpůsobeného rozhraní).
Když poskytovatel získá aktualizační požadavek, je generována událost OnUpdateData,
kde
můžeme editovat
Delta
paket a to dříve než je zapsán do datové množiny nebo
ovlivňovat
jak jsou aktualizace aplikovány. Po události OnUpdateData, poskytovatel
použije svou přiřazenou komponentu řešitele k zápisu změn do databáze.
Komponenta řešitele provádí aktualizace záznam po záznamu.
Dříve než řešitel aplikuje každý záznam, generuje na poskytovateli událost
BeforeUpdateRecord,
kterou
můžeme použít k
monitorování
aktualizací před jejich aplikací. Když při aplikování záznamu vznikne
chyba, pak řešitel volá obsluhu události OnUpdateError poskytovatele
k
řešení
chyb. Chyby obvykle vznikají, protože změny porušují serverová omezení
nebo když záznam databáze byl změněn jinou aplikací po jeho získání naší
klientskou aplikací, ale před klientským požadavkem na aplikování aktualizací.
Chyby aktualizace mohou být zpracovány aplikačním serverem
nebo klientem. Aplikační server zpracuje všechny chyby aktualizace, které
k řešení nevyžadují interakci uživatele. Když aplikační server nemůže vyřešit
chybovou podmínku, je dočasně uložena kopie ovlivňovaných záznamů. Po dokončení
zpracování záznamů, aplikační server vrací počet vyskytnuvších se chyb
klientské datové množině a kopie nevyřešených záznamů v paketu výsledkové
množiny, který je předán zpět klientovi k budoucímu zpracování.
Poznámka: Komponenta uložené procedury nemůže
být aktualizována tímto mechanismem. K aplikaci aktualizací na uloženou
proceduru musíme provést jedno z:
-
Přidat kód k explicitnímu aplikování aktualizací v události
BeforeUpdateRecord
poskytovatele. Obvykle to vyřešíme použitím další komponenty TStoredProc
pro vkládání, rušení nebo modifikaci záznamů.
-
Předáme jméno tabulky, které řešitel může použít když
generuje SQL k aplikování aktualizací. Tato možnost pracuje pouze, když
uložená procedura reprezentuje záznamy z jedné tabulky. Specifikujeme jméno
tabulky jako vlastnost Table_Name datového paketu a požadujeme aby
byla vložena do Delta paketu. Na přidávání vlastností do datového
paketu se podívejte na Přidávání
přizpůsobených informací do datových paketů.
Obsluhy událostí pro všechny události poskytovatele přebírají
množinu aktualizací jako klientská datová množina. Pokud obsluha událostí
je určena pouze pro jisté typy aktualizací, pak můžeme datovou množinu
filtrovat na základě stavu aktualizace záznamů a tak naše obsluha událostí
nemusí procházet záznamy, které nepoužije. K tomuto, nastavíme vlastnost
StatusFilter
klientské datové množiny.
Editování Delta
paketů před aktualizováním databáze
Dříve než poskytovatel aplikuje aktualizace na databázi,
generuje událost
OnUpdateData. Obsluha události OnUpdateData
získá kopii paketu
Delta jako parametr. Je to klientská datová množina.
V obsluze události OnUpdateData můžeme používat
libovolné vlastnosti a metody klientské datové množiny k editaci paketu
Delta
před jeho zápisem do datové množiny. Nejužitečnější vlastností je UpdateStatus.
UpdateStatus
indikuje jaký typ modifikace současný záznam v paketu Delta reprezentuje.
Mohou být použity hodnoty z následující tabulky:
Hodnota |
Popis |
usUnmodified |
Obsah záznamu není změněn. |
usModified |
Obsah záznamu má být změněn. |
usInserted |
Záznam má být vložen. |
usDeleted |
Záznam má být zrušen. |
Např. následující obsluha události OnUpdateData
vkládá současné datum do každého nového záznamu, který je vložen do databáze:
void __fastcallTMyDataModule1::Provider1UpdateData(TObject
*Sender,
TClientDataSet *DataSet)
{
DataSet->First();
while(!DataSet->Eof)
{
if (DataSet->UpdateStatus
== usInserted)
{
DataSet->Edit();
DataSet->FieldByName("DateCreated")->AsDateTime
= Date();
DataSet->Post();
}
DataSet->Next();
}
}
Ovlivňování jak
aktualizace jsou aplikovány
Událost OnUpdateData dává našemu poskytovateli možnost
indikovat jak záznamy v paketu Delta jsou aplikovány do databáze.
Implicitně, změny v paketu Delta jsou zapsány do databáze pomocí
automaticky generovaného SQL příkazu UPDATE, INSERT nebo DELETE, jako:
UPDATE EMPLOYEES
set EMPNO = 748, NAME = 'Smith', TITLE
= 'Programmer 1', DEPT = 52
WHERE
EMPNO = 748 and NAME = 'Smith' and
TITLE = 'Programmer 1' and DEPT = 47
Pokud nespecifikujeme něco jiného, pak všechny položky
v záznamech paketu Delta jsou vloženy do klauzule UPDATE a do klauzule
WHERE. Nicméně můžeme chtít vyloučit některé tyto položky. Jednou z možností,
jak to provést je nastavit vlastnost UpdateMode poskytovatele. UpdateMode
můžeme přiřadit některou z těchto hodnot:
Hodnota |
Význam |
upWhereAll |
Všechny položky jsou použity k lokalizaci (klauzule WHERE). |
upWhereChanged |
Pouze klíčové položky a změněné položky jsou použity
k lokalizaci záznamů. |
upWhereOnly |
K lokalizaci záznamů jsou použity pouze klíčové položky. |
Můžeme ale požadovat více řízení. Např. s předchozím příkazem,
můžeme chtít zabránit položce EMPNO v modifikaci vyloučením z klauzule
UPDATE a položky TITLE a DEPT vyloučit z klauzule WHERE k zabránění aktualizačním
konfliktům, když ostatní aplikace modifikují data. Ke specifikaci klauzulí,
kde se specifikované položky vyskytnou, použijeme vlastnost ProviderFlags.
ProviderFlags
může obsahovat libovolné hodnoty z následující tabulky:
Hodnota |
Popis |
pfInWhere |
Položka neuváděná v klauzuli WHERE generovaných příkazů
INSERT, DELETE a UPDATE. |
pfInUpdate |
Položka neuváděná v klauzuli UPDATE generovaného příkazu
UPDATE. |
pfInKey |
Tato položka je použita v klauzuli WHERE generovaného
příkazu SELECT, který je proveden při výskytu chyb aktualizace. Tento příkaz
SELECT získá současné hodnoty modifikovaných nebo zrušených záznamů nebo
záznamů způsobujících porušení klíče při vkládání. |
pfHidden |
Položka je vložena do záznamu k zajištění unikátnosti,
ale není viditelná nebo použitelná na klientské straně. |
Tedy, následující obsluha události OnUpdateData
vyloučí položku EMPNO z klauzule UPDATE a položky TITLE a DEPT z klauzule
WHERE:
void __fastcallTMyDataModule1::Provider1UpdateData(TObject
*Sender,
TClientDataSet *DataSet)
{
DataSet->FieldByName("EMPNO")->UpdateFlags.Clear();
DataSet->FieldByName("EMPNO")->UpdateFlags
<< ufInUpdate;
DataSet->FieldByName("TITLE")->UpdateFlags.Clear();
DataSet->FieldByName("TITLE")->UpdateFlags
<< ufInWhere;
DataSet->FieldByName("DEPT")->UpdateFlags.Clear();
DataSet->FieldByName("DEPT")->UpdateFlags
<< ufInWhere;
}
Poznámka: Vlastnost UpdateFlags můžeme
použít k ovlivnění jak aktualizace jsou aplikovány, když aktualizujeme
datovou množinu a nepoužíváme dynamicky generované SQL. Tyto příznaky stále
určují, které položky jsou použity k lokalizaci záznamů a které k zadávání
aktualizací.
Monitorování individuálních
aktualizací
Bezprostředně před aplikováním každé aktualizace, poskytovatel
získá událost
BeforeUpdateRecord. Tuto událost můžeme použít k editaci
záznamů před jejich aplikováním a to podobně jako můžeme použít událost
OnUpdateData
k editaci celých
Delta
paketů. Např. poskytovatel neporovnává položky
BLOB, když testuje konflikty aktualizace. Pokud chceme testovat konflikty
aktualizace včetně položek BLOB, pak k tomu můžeme použít událost BeforeUpdateRecord.
Dále tuto událost můžeme použít k samotnému aplikování
aktualizací nebo k zobrazení a odmítnutí aktualizací. Obsluha události
BeforeUpdateRecord
signalizuje řešiteli, že aktualizace již byla zpracována a tedy že nemá
být aplikována. Řešitel pak tento záznam přeskočí, ale nezapočítává jej
jako chybu aktualizace. Např. tato událost poskytuje mechanismus pro aplikování
aktualizací pro uložené procedury (které nemohou být aktualizovány automaticky),
umožněním poskytovateli přeskočit libovolný automatický proces na záznamu,
při jeho aktualizování v obsluze události.
Řešení aktualizačních
chyb na poskytovateli
Když chybová podmínka je porušena při odesílání záznamu v
Delta
paketu aplikačním serverem, pak vzniká událost OnUpdateError. Pokud
aplikační server nemůže vyřešit chybu aktualizace, je dočasně uložena kopie
ovlivňovaného záznamu. Po dokončení zpracování záznamů, aplikační server
vrací počet vyskytnuvších se chyb klientské datové množině a kopie nevyřešených
záznamů v paketu výsledkové množiny, jsou předány zpět klientovi pro jejich
budoucí vyřešení.
Tento mechanismus umožňuje zpracovat libovolné chyby
aktualizace, které nemohou být vyřešeny mechanicky na aplikačním serveru,
a vyžadují pro vyřešení zásahy uživatele v klientské aplikaci.
Obsluha OnUpdateError získá kopii záznamu, který
nemohl být změněn a chybový kód od databáze a indikaci zda řešitel se pokusil
vložit, zrušit nebo aktualizovat záznam. Problémový záznam je předán zpět
v datové množině. Na této datové množině nesmíme nikdy použit metody navigace
dat. Můžeme ale, pro každou položku v datové množině použít vlastnosti
NewValue,
OldValue
a CurValue k určení problému a provést nějakou modifikaci k vyřešení
aktualizační chyby. Pokud obsluha události OnUpdateError může problém
opravit, pak nastavíme parametr
Response a tak opravený záznam je
aplikován.
Reagování na události
generované klientem
Komponenta poskytovatele implementuje obecnou událost, která
umožňuje vytvářet své vlastní volání z klienta přímo poskytovateli. Je
to událost OnDataRequest.
OnDataRequest nepatří do normální funkčnosti poskytovatele.
Je to jednoduchá možnost umožňující našim klientům použít rozhraní IProvider
k přímé komunikaci s poskytovateli na aplikačním serveru. Tato obsluha
události přebírá OleVariant jako vstupní parametr a vrací OleVariant.
Pomocí OleVariant, rozhraní je schopno předat libovolnou informaci
na nebo z poskytovatele.
Ke generování události OnDataRequest, klientská
aplikace volá metodu DataRequest rozhraní IProvider přímo.
V beze stavových vzdálených datových modulech, přizpůsobené rozhraní na
vzdáleném datovém modulu může volat metodu DataRequest objektu poskytovatele.
Zpracování serverových omezení
Většina systémů správy relačních databází implementuje omezení
na svých tabulkách k zajištění integrity dat. Omezení je pravidlo, které
vládne nad hodnotami v tabulkách a sloupcích nebo které ovládá vzájemné
vztahy dat mezi sloupci v různých tabulkách. Např. většina relačních databází
splňujících SQL-92 podporuje následující omezení:
-
NOT NULL, k zajištění, že hodnota předaná do sloupce má hodnotu.
-
NOT NULL UNIQUE, k zajištění, že sloupec má hodnotu která
se neshoduje se žádnou jinou hodnotou v tomto sloupci v jiném záznamu.
-
CHECK, k zajištění, že hodnota předaná sloupci je v jistém
rozsahu nebo je jedna z omezeného počtu předaných hodnot.
-
CONSTRAINT, testování na úrovni tabulky, které je aplikováno
na více sloupců.
-
PRIMARY KEY, k určení jednoho nebo více sloupců jako primárního
klíče tabulky pro účely indexování.
-
FOREIGN KEY, k určení jednoho nebo více sloupců v tabulce
které ukazují na jinou tabulku.
Poznámka: Tento seznam není výlučný. Náš databázový
server může podporovat některá nebo všechna tato omezení a to částečně
nebo úplně a může podporovat další omezení. Více informací o podporovaných
omezeních zjistíme v dokumentaci našeho databázového serveru.
Omezení databázového serveru obvykle nahrazují mnoho
typů testování dat, které aplikace tradičních relačních databází spravovaly
v minulosti. Můžeme převzít výhody serverových omezení ve více vrstvových
databázových aplikacích bez nutnosti duplikování omezení v kódu aplikačního
serveru nebo klientské aplikace.
Vlastnost Constraints poskytovatele umožňuje replikovat
a aplikovat serverová omezení na data předávaná na a získávaná z klientských
aplikací. Když Constraints je true (implicitně), pak serverová
omezení jsou replikována na klienty a ovlivňují klientské pokusy o aktualizaci
dat.
Poznámka: Někdy nemusíme požadovat aplikování
serverových omezení na data zasílaná klientskými aplikacemi. Např. klientská
aplikace může získávat data v paketech a umožňovat lokální aktualizace
záznamů před získáním dalších záznamů může požadovat zakázat některá serverová
omezení, protože je používána nekompletní množina dat. K zabránění replikování
omezení z aplikačního serveru na klientskou datovou množinu, nastavíme
Constraints
na false. Nezapomeňte také, že klientské datové množiny mohou zakazovat
a povolovat omezení pomocí metod DisableConstraints a EnableConstraints.
Vytváření klientské aplikace
V mnoha ohledech, vytváření více vrstvové klientské aplikace
se podobá vytváření tradičního dvouvrstvého klienta. Hlavní odchylky použité
ve více vrstvovém klientovi jsou:
-
Komponenta propojení pro zřízení spojení s aplikačním serverem.
-
Jedna nebo více komponent TClientDataSet propojených
na poskytovatele dat na aplikačním serveru. Datové ovladače na klientu
jsou připojeny prostřednictvím komponent datových zdrojů k těmto klientským
datovým množinám, namísto ke komponentám TTable, TQuery a
TStoredProc.
K vytvoření více vrstvové klientské aplikace, začneme nový
projekt a provedeme tyto kroky:
-
Přidáme k projektu nový datový modul.
-
Na datový modul umístíme komponentu připojení. Typ přidané
komponenty připojení závisí na používaném komunikačním protokolu. Viz Struktura
klientských aplikací.
-
Nastavíme vlastnosti naší komponenty připojení na specifikaci
aplikačního serveru, ke kterému chceme zřídit připojení. Více o nastavování
komponent připojení se dozvíme v Připojování
na aplikační server.
-
Nastavíme další vlastnosti komponent připojení podle potřeby
naší aplikace. Např. můžeme nastavit vlastnost ObjectBroker k umožnění
komponentě připojení dynamicky volit z několika serverů.
-
Umístíme potřebný počet komponent TClientDataSet do
datového modulu a nastavíme vlastnost RemoteServer pro každou komponentu
na jméno komponenty připojení umístěné v kroku 2.
-
Nastavíme vlastnost ProviderName pro každou komponentu
TClientDataSet.
Pokud naše komponenta připojení je připojena na aplikační server při návrhu,
pak můžeme zvolit dostupný aplikační server v rozbalovacím seznamu vlastnosti
ProviderName.
Při používání beze stavových vzdálených datových modulu je možno tento
krok přeskočit.
-
Vytvoříme klientskou aplikaci stejným způsobem jako vytváříme
jiné databázové aplikace. Můžeme ale přidávat kód a nastavovat vlastnosti
pro
Připojování na aplikační
server
Pro zřízení a udržování připojení na aplikační server, klientská
aplikace používá jednu nebo více komponent připojení. Tyto komponenty můžeme
nalézt na stránce MIDAS Palety komponent.
Komponentu připojení použijeme k:
-
Identifikujeme protokol pro komunikaci s aplikačním serverem.
Každý typ připojovací komponenty reprezentuje jiný typ komunikačního protokolu.
Podrobnosti naleznete ve Volba
komunikačního protokolu.
-
Určíme jak lokalizovat počítač serveru. Detaily identifikace
počítače serveru závisí na protokolu. Na detaily se podívejte do následujících
bodů:
-
Identifikujeme aplikační server na počítači serveru pomocí
vlastností ServerName nebo ServerGUID. ServerName
identifikuje základní jméno třídy specifikované při vytváření vzdáleného
datového modulu na aplikačním serveru. Detaily nalezneme v Nastavování
vzdáleného datového modulu. Pokud server je registrován nebo instalován
na klientském počítači nebo pokud komponenta připojení je připojena na
počítač serveru, pak můžeme nastavit vlastnost ServerName při návrhu
volbou z rozbalovacího seznamu v Inspektoru objektů. ServerGUID
specifikuje
GUID rozhraní vzdáleného datového modulu. Tuto hodnotu
si můžeme prohlédnout pomocí Editoru knihovny typů.
-
Správa serverového
připojení. Komponenty připojení mohou být použity k vytvoření nebo
rušení připojení a k volání rozhraní aplikačního serveru.
Obvykle aplikační server je na jiném počítači než klientská
aplikace, ale pokud server sídlí na stejném počítači jako klientská aplikace
(např. v průběhu budování a testování celé více vrstvové aplikace), pak
stále můžeme používat komponentu připojení k identifikaci aplikačního serveru
jménem, specifikaci počítače serveru a použití rozhraní aplikačního serveru.
Specifikace
připojení pomocí DCOM
Když pro komunikaci s aplikačním serverem používáme DCOM,
pak klientská aplikace obsahuje komponentu TDCOMConnection pro připojování
na aplikační server. TDCOMConnection používá vlastnost ComputerName
k identifikaci počítače na kterém sídlí server.
Když ComputerName je prázdné, pak komponenta připojení
DCOM předpokládá, že aplikační server sídlí na klientském počítači nebo
že aplikační server má položku v systémových registrech. Pokud neposkytneme
položky systémového registru pro aplikační server na klientu při používání
DCOM a server sídlí na jiném počítači než server, pak musíme zadat ComputerName.
Poznámka: I když je položka systémového registru
pro aplikační server, pak můžeme použít ComputerName k přepsání
této položky. To je obzvláště užitečné pro vývoj, testování a ladění.
Pokud předáme jméno hostitelského počítače nebo serveru,
který nemůže být nalezen, pak komponenta připojení DCOM generuje výjimku,
když se pokusí otevřít připojení.
Pokud máme více serverů, mezi kterými naše klientská
aplikace může volit, pak můžeme použít vlastnost ObjectBroker místo
specifikování hodnoty pro ComputerName. Více informací viz Agentování
připojení.
Specifikování
připojení pomocí soketů
Připojení na aplikační server pomocí soketů můžeme zřídit
na libovolném počítači, který má adresu TCP/IP. Tato metoda má výhodu,
že je aplikovatelná na mnoha počítačích, ale nenabízí k použití žádný bezpečnostní
protokol. Když používáme sokety, pak vložíme pro připojení na aplikační
server komponentu TSocketConnection.
TSocketConnection identifikuje počítač serveru
pomocí IP adresy nebo hostitelského jména systému serveru a číslem portu
programu vyřízujícího sokety (Scktsrvr.exe nebo Scktsrvc.exe),
který je spuštěn na počítači serveru.
Adresu IP a číslo portu specifikují tyto vlastnosti TSocketConnection:
-
Address specifikuje IP adresu serveru.
-
Host specifikuje hostitelské jméno serveru.
-
Port specifikuje číslo portu programu vyřizujícího
sokety na aplikačním serveru.
Address a Host se vzájemně vylučují. Nastavení
jedné zruší hodnotu druhé.
Pokud máme více serverů, ze kterých naše klientská aplikace
může volit, pak místo nastavování hodnot vlastnosti Address nebo
Host,
můžeme použít vlastnost ObjectBroker. Více informací viz Agentování
připojení.
Implicitně, hodnota Port je 211, což je implicitní
číslo portu programu vyřizujícího sokety dodaného s C++ Builderem. Pokud
vyřizovač soketů je konfigurován na použití jiného portu, pak nastavíme
Port
na tuto hodnotu.
Poznámka: Konfigurovat port Vyřizovače soketu
za běhu můžeme kliknutím pravým tlačítkem myši na jeho ikoně.
Specifikování
připojení pomocí OLEnterprise
Když pro komunikaci s aplikačním serverem používáme OLEnterprise,
pak klientská aplikace musí vložit pro připojení na aplikační server
komponentu TOLEnterproseConnection. Když používáme OLEnterprise,
pak se můžeme připojovat na počítač serveru přímo nebo můžeme použít Business
Object Broker.
K použití OLEnterprise bez Business Object Broker, nastavíme
vlastnost
ComputerName na jméno počítače serveru a to stejně jako
používáme vlastnost ComputerName pro připojení DCOM. K použití Business
Object Broker, nastavíme vlastnost
BrokerName na jméno Business
Object Broker.
ComuterName a BrokerName se vzájemně vylučují.
Nastavení hodnoty jedné vlastnosti ruší hodnotu druhé.
Agentování připojení
Pokud máme více serverů, ze kterých klientská aplikace
může volit, pak můžeme použít Object Broker k lokalizaci dostupného
serverového systému. Objekt agenta udržuje seznam serverů ze kterých komponenta
připojení může volit. Když se komponenta připojení potřebuje připojit k
aplikačnímu serveru, pak se ptá Objektu agenta na jméno počítače (nebo
IP adresu případně jméno hostitele). Agent předává jméno počítače a komponenta
připojení formuje připojení. Pokud předané jméno nepracuje (např. server
je zastaven), pak Agent předá jiné jméno atd. dokud připojení není navázáno.
Po zformování připojení připojovací komponentou s jménem
předaným Agentem, je jméno uloženo jako hodnota odpovídající vlastnosti
(ComputerName,
Address nebo Host). Pokud připojovací
komponenta později připojení uzavře, pak při pokusu o opětovné otevření
připojení se použijí tyto uložené hodnoty a pouze při neúspěchu připojení
je Agent dotazován na nové jméno.
Objekt agenta použijeme specifikováním vlastnosti ObjectBroker
naší připojovací komponenty. Když vlastnost ObjectBroker je nastavena,
pak připojovací komponenta neukládá hodnoty ComputerName, Address
nebo Host.
Poznámka: Vlastnost ObjectBroker nepoužíváme
s připojením OLEnterprise. OLEnterprise má své vlastní agentovací služby.
Spravování serverových připojení
Hlavním významem připojovacích komponent je lokalizovat a
připojit se k aplikačnímu serveru. Protože spravují serverové připojení,
můžeme také použít komponentu připojení k volání metod rozhraní aplikačního
serveru.
Následující body popisují jak používat připojovací komponentu
pro:
Připojování na
server
K lokalizaci a připojení na databázový server, musíme
nejprve nastavit vlastnosti komponenty připojení k identifikaci aplikačního
serveru. Tento proces je popsán v Připojování
na aplikační server. Dále před otevřením připojení, libovolné klientské
datové množiny, které používají připojovací komponentu, k získání rozhraní
IProvider,
musí to indikovat nastavením jejich vlastností RemoteServer ke specifikování
připojovací komponenty. Klientské datové množiny pak nastaví jejich vlastnosti
ProviderName
před otevřením připojení a tak když připojení je otevřeno, můžeme získat
příslušné rozhraní IProvider.
Připojení je otevřeno automaticky, když klientská datová
množina se pokusí zpřístupnit rozhraní IProvider. Např. nastavením
vlastnosti
Active klientské datové množiny na true otevřeme
připojení.
Pokud nepřipojíme klientskou datovou množinu na připojovací
komponentu aby mohla používat rozhraní IProvider, pak můžeme otevřít
připojení nastavením vlastnosti Connected komponenty připojení na
true.
Před zřízením připojení připojovací komponenty na aplikační
server, je generována událost BeforeConnect. Můžeme provést nějaké
potřebné speciální akce před připojením v kódu obsluhy událostí BeforeConnect.
Po zřízení připojení, připojovací komponenta generuje událost AfterConnect
pro další speciální akce.
Rušení
nebo změna serverového připojení
Komponenta připojení zruší připojení na aplikační server
když:
-
Nastavíme vlastnost Connected na false.
-
Uvolníme připojovací komponentu. Připojovací objekt je automaticky
uvolněn, když uživatel uzavře klientskou aplikaci.
-
Změnou libovolné vlastnosti identifikující aplikační server
(ServerName,
ServerGUID,
ComputerName apod.). Změnou
těchto vlastností se můžeme přepnout na jiný dostupný aplikační server
za běhu. Připojovací komponenta zruší současné připojení a zřídí nové.
Poznámka: Místo používání jedné připojovací komponenty
k přepínání mezi dostupnými aplikačními servery, klientská aplikace může
mít více připojovacích komponent, kde každá z nich je připojena na jiný
aplikační server.
Dříve než připojovací komponenta ukončí připojení, je
automaticky volána obsluha události BeforeDisconnect, pokud je poskytnuta.
Pokud potřebujeme provést nějakou speciální akci před odpojením, pak ji
zapíšeme do obsluhy
BeforeDisconnect. Podobně, po ukončení připojení
je volána obsluha události AfterDisconnect. Pokud potřebujeme provést
nějakou speciální akci po ukončení připojení, pak je musíme zapsat zde.
Volání rozhraní
serveru
Aplikace nepotřebuje volat rozhraní IProvider
přímo, protože příslušná volání jsou provedena automaticky, když používáme
vlastnosti a metody klientské datové množiny. Jedinou podstatnou výjimkou
je přímé volání metody DataRequest poskytovatele na aplikačním serveru.
Více informací o používání DataRequest nalezneme v Reagování
na klientem generované události. Když potřebujeme volat rozhraní poskytovatele,
pak můžeme použít vlastnost Provider klientské datové množiny, která
reprezentuje data od poskytovatele.
I když klientská aplikace nepotřebuje volat rozhraní
IDataBroker
aplikačního serveru, může přidávat své vlastní rozšíření k rozhraní aplikačního
serveru. Když rozšíříme rozhraní aplikačního serveru, pak potřebujeme nalézt
způsob volání tohoto rozšíření pomocí připojení vytvořeného naší komponentou
připojení. Můžeme to provést pomocí vlastnosti
AppServer připojovací
komponenty. AppServer je Variant, který reprezentuje rozhraní
aplikačního serveru. K volání tohoto rozhraní, musíme vyřizující rozhraní
získat z této Variant. Toto vyřizující rozhraní má stejné jméno
jako rozhraní vytvořené při vytváření vzdáleného datového modulu, ale má
přidaný řetězec Disp. Tedy pokud náš vzdálený datový modul se nazývá
MyAppServer,
pak můžeme použít AppServer k volání svého rozhraní takto:
IMyAppServerDisp TempInterface(LPDISPATCH(MyConnection->AppServer));
TempInterface->SpecialMethod(x,y);
Zpracování omezení
Omezení databázového serveru a implicitní výrazy mohou být
importovány do Datového slovníku pomocí průzkumníka SQL. Omezení a implicitní
výrazy v Datovém slovníku jsou automaticky dostupné pro datové množiny
podporující BDE v aplikačním serveru. Implicitně, serverová omezení a implicitní
výrazy jsou předávány klientským datovým množinám aplikačním serverem,
a můžeme je potom využívat při editaci dat uživatelem. Když omezení jsou
v činnosti, pak editace dat v klientské aplikaci, které nesplňují serverová
omezení jsou zachycena na klientské straně, a nejsou předávána na aplikační
server. Tím je snížen počet chyb generovaných v průběhu aktualizačního
procesu.
Během importování serverových omezení a výrazů je nejdůležitější
službou chránit integritu dat mezi platformami a aplikacemi a mohou být
okamžiky, kdy vývojář potřebuje dočasně zakázat omezení. Např. pokud serverové
omezení je založené na současné maximální hodnotě v položce, pak na klientu
se může tato hodnota lišit od hodnoty na databázovém serveru a omezení
mohou pracovat různě. V jiném případě, pokud klientská aplikace aplikuje
na záznamy filtr při povoleném omezení, pak filtr může interferovat nějakým
způsobem s podmínkou omezení. Ve všech těchto případech aplikace může zakázat
testování omezení.
K dočasnému zákazu omezení voláme metodu DisableConstraints
klientské datové množiny. Při každém volání DisableConstraints je
inkrementován čítač odkazů. Pokud hodnota tohoto čítače je větší než nula,
pak omezení nejsou vnucována klientské datové množině.
K obnovení omezení pro klientskou datovou množinu, voláme
metodu EnableConstraints. Každé volání EnableConstraints
dekrementuje čítač odkazů. Když čítač odkazů je nula, pak omezení jsou
opět povolena.
Tip: Volání DisableConstraints a EnableConstraints
tvoří pár k zajištění, že omezení jsou povolena, když chceme aby byla.
Aktualizování záznamů
Když klientská aplikace je připojena na aplikační server,
pak klientské datové množiny pracují s lokální kopií dat předaných z aplikačního
serveru. Uživatel vidí a edituje tuto kopii v datových ovladačích klientské
aplikace. Pokud serverová omezení jsou povolena na klientské datové množině,
pak jsou stejně omezena editace uživatele. Uživatelské změny jsou dočasně
uloženy klientskou datovou množinou v interně udržovaném deníku změn. Obsah
deníku změn je ukládán jako datový paket ve vlastnosti Delta. K
udělání změn v Delta trvalými, klientská datová množina je musí
aplikovat do databáze.
Když klient aplikuje aktualizace na server pomocí rozhraní
IProveder,
pak proběhnou následující kroky:
-
Klientská aplikace volá
metodu ApplyUpdates objektu klientské datové množiny. Tato metoda
předává obsah vlastnosti
Delta klientské datové množiny na aplikační
server prostřednictvím rozhraní IProvider současně přiřazeného ke
klientské datové množině.
Delta je datový paket, který obsahuje
aktualizace, vkládání a rušení záznamů v klientské datové množině.
-
Komponenta poskytovatele aplikačního serveru aplikuje aktualizace
do databáze a odkládá všechny problémové záznamy, které nelze vyřešit na
úrovni serveru. Viz Řešení aktualizačních
konfliktů při aplikování aktualizací serverem.
-
Komponenta poskytovatele aplikačního serveru vrací všechny
nevyřešené záznamy na klienta v datovém paketu Result. Datový paket
Result
obsahuje všechny záznamy, které nemohly být aplikovány. Také obsahuje chybové
informace, jako jsou chybové zprávy a chybové kódy.
-
Klientská aplikace se pokusí vyřešit chyby aktualizací vrácených
v datovém paketu Result záznam po záznamu.
Poznámka: Pokud používáme transakce MTS nebo
aktivaci just-in-time, pak nemůžeme použít rozhraní IProvider k
aplikování aktualizací. Tento proces musíme provést pomocí rozhraní aplikačního
serveru. Více informací naleznete v Podporování
beze stavových vzdálených datových modulů.
Aplikování
aktualizací
Změny provedené na lokální kopii dat klientské datové
množiny nejsou zasílány na aplikační server dokud klientská aplikace nezavolá
pro datovou množinu metodu ApplyUpdates. ApplyUpdates přebírá
jeden parametr,
MaxErrors, určující maximální počet chyb, které
aplikační server bude tolerovat před zrušením aktualizačního procesu. ApplyUpdates
vrací skutečný počet vzniklých chyb, který je vždy menší nebo roven MaxErrors+1.
Tato hodnota je nastavena k indikaci počtu záznamů, které nebyly zapsány
do databáze. Aplikační server také vrací tyto záznamy na klientskou datovou
množinu v datové množině.
Klientská datová množina je zodpovědná za vyřešení konfliktů
pro záznamy, které generují chyby. ApplyUpdates aktuálně volá metodu
Reconcile
klienské datové množiny k zaslání aktualizací na aplikační server a Reconcile
vyvolá obsluhu události OnReconcileError klientské datové množiny
(pokud existuje), vždy pro každý záznam, který generoval chybu na serveru.
Řešení
aktualizačních konfliktů
Poskytovatel na aplikačním serveru vrací chybné záznamy
a chybové informace na klientskou datovou množinu v datovém paketu Result.
Pokud aplikační server vrátí počet chyb větší než 0, pak pro každý záznam
v datovém paketu
Result vzniká událost OnReconcileErrors
klientské datové množiny.
Pokud nechceme pouze ignorovat záznamy vrácené aplikačním
serverem, pak musíme poskytnout kód obsluze události OnReconcileError.
Obsluha události OnReconcileError má čtyři parametry:
-
DataSet: klientská datová množina, ve které aktualizace
jsou aplikovány. Můžeme použít metody klientské datové množiny k získání
informací o problémových záznamech a provést změny na záznamech k odstranění
problémů. K tomu můžeme použít vlastnosti CurValue, OldValue
a NewValue položek v současném záznamu k určení odstranění aktualizačního
problému. Nesmíme ale volat žádné metody klientské datové množiny, které
mění současný záznam (přecházejí na jiný) v obsluze události OnReconcileError.
-
E: Objekt EReconcileError reprezentující vzniklý
problém. Tuto výjimku můžeme použít k extrakci chybové zprávy nebo určení
typu aktualizační chyby.
-
UpdateKind: typ aktualizace generující chybu. UpdateKind
může být ukModify (problém vznikl aktualizací existujícího záznamu,
který byl modifikován), ukInsert (problém vznikl vložením nového
záznamu) nebo ukDelete (problém vznikl zrušením existujícího záznamu).
-
Action: odkazový parametr určující jakou akci provést
po ukončení obsluhy OnReconcileError. V obsluze Action nastavíme
na požadovanou akci v řešícím procesu na serveru. Můžeme použít následující
hodnoty:
-
Přeskočení tohoto záznamu, s jeho zanecháním v deníku změn
(raSkip).
-
Zastavení celé operace konsolidace (raAbort).
-
Spojení chybné modifikace s odpovídajícím záznamem ze serveru
(raMerge). Toto pracuje pouze, když server nezměnil žádné položky
modifikované uživatelem.
-
Nahrazení současných aktualizací v deníku změn hodnotami
záznamu v obsluze události; které byly předem opraveny (raCorrect).
-
Zrušení změn na tomto záznamu v klientské datové množině,
návratem k původně poskytnutým hodnotám (raCancel).
-
Aktualizace hodnot současného záznamu na hodnoty tohoto záznamu
na serveru (raRefresh).
Následující kód ukazuje obsluhu události OnReconcileError,
která používá dialogové okno řešení chyb z jednotky RecError, kterou
najdeme v adresáři zásobníku objektů (k použití tohoto dialogu vložíme
hlavičkový soubor RecError.hpp do kódu naší jednotky).
void __fastcall TForm1::ClientDataSetReconcileError(TClientDataSet
*DataSet,
EReconcileError
*E, TUpdateKind UpdateKind, TReconcileAction &Action)
{
Action = HandleReconcileError(DataSet,
UpdateKind, E);
}
Obnovování záznamů
Klientská aplikace pracuje s kopií dat z aplikačního serveru.
V průběhu času ostatní uživatelé mohou modifikovat tato data a tak naše
klientská aplikace má již zastaralou kopii dat. Stejně jako jiné datové
množiny i klientská datová množina má metodu Refresh, která aktualizuje
své hodnoty na současné hodnoty na serveru. Volání Refresh pracuje
pouze, když deník změn je prázdný. Volání Refresh při neaplikovaných
aktualizacích generuje výjimku.
Klientská aplikace může také aktualizovat data při nedotčení
deníku změn. Provedeme to voláním metody RefreshRecord klientské
datové množiny. Na rozdíl od metody Refresh, metoda RefreshRecord
aktualizuje pouze současný záznam v datové množině. RefreshRecord změní
hodnoty záznamu původně získané z aplikačního serveru, ale ztratí všechny
změny v deníku změn.
Varování: Ne vždy je vhodné volat RefreshRecord.
Při vzniku konfliktu se změnami provedenými jinými uživateli v připojené
datové množině, volání RefreshRecord tento konflikt zamaskuje. Když
klientská aplikace aplikuje své aktualizace, pak žádný konflikt nevzniká
a aplikace jej nemusí řešit.
K zabránění maskování aktualizačních chyb, klientská
aplikace může testovat, zda jsou nevyřízené aktualizace před voláním RefreshRecord.
Např. následující kód generuje výjimku, pokud se pokusíme obnovit modifikovaný
záznam:
if (ClientDataSet1->UpdateStatus != usUnModified)
throw Exception
("You must apply updates
before refreshing the current record.");
ClientDataSet1->RefreshRecord;
Získávání parametrů
z aplikačního serveru
Jsou dvě situace, kdy klientská aplikace potřebuje získat
hodnoty parametrů z aplikačního serveru:
-
Klient potřebuje znát hodnotu výstupního parametru uložené
procedury.
-
Klient potřebuje inicializovat vstupní parametry dotazu nebo
uložené procedury na současnou hodnotu TQuery nebo TStoredProc
na aplikačním serveru.
Klient požaduje hodnotu parametrů z aplikačního serveru voláním
metody
FetchParams. Parametry jsou vráceny v datových paketech z
aplikačního serveru a přiřazeny vlastnosti Params klientské datové
množiny.
Při návrhu, vlastnost Params můžeme inicializovat
volbou Fetch Params v místní nabídce klientské datové množiny.
Poznámka: Metoda FetchParams (nebo volba
Fetch
Params) pracuje pouze tehdy, pokud klientská datová množina je připojena
k poskytovateli, který umí předávat parametry. TProvider může předávat
parametry, pokud reprezentuje TQuery nebo TStoredProc.
Vlastnost Params může být také použita k zasílání
hodnot parametrů na aplikační server. Tím jsme se ale již zabývali v minulé
kapitole.
Přizpůsobování aplikačního
serveru
Architektura MIDAS je značně flexibilní a tak můžeme přizpůsobit
aplikační server k zajištění specifických potřeb naší aplikace. Např. můžeme:
Rozšiřování rozhraní
aplikačního serveru
Klientská aplikace spolupracuje s aplikačním serverem implementací
třídy vytvořené Průvodcem vzdáleným datovým modelem nebo Průvodcem datovým
modelem MTS. Používá své rozhraní jako základ všech komunikací s aplikačním
serverem. Jediná výjimka z tohoto pravidla je, když klientská datová množina
se dotazuje přímo komponenty poskytovatele pomocí rozhraní IProvider.
Když používáme transakce nebo aktivizaci just-in-time
pod MTS, pak je obzvláště důležité, aby všechna komunikace s aplikačním
serverem probíhala prostřednictvím implementované třídy rozhraní. Libovolná
jiná komunikace obcházející proxy MTS, může způsobit chyby.
Můžeme k naší implementaci třídy rozhraní přidávat další
funkce k poskytnutí další podpory pro naše klientské aplikace. Toto rozhraní
je potomkem IDataBroker a je vytvořeno automaticky Průvodcem při
vytváření vzdáleného datového modulu. Pro přidání k implementaci třídy
rozhraní použijeme Editor knihovny typů.
Když přidáváme k rozhraní COM, pak naše změny jsou přidávány
k naší jednotce zdrojového kódu a souboru knihovny typů (TLB).
Poznámka: Soubor TLB není uložen, dokud ji
neuložíme z Editoru knihovny typů nebo v IDE nezvolíme File | Save All.
Když již máme přidány k naši implementaci třídy rozhraní,
umístíme vlastnosti a metody které jsme přidávali k naši implementaci třídy.
Kod přidáme na konec této implementace.
Klientská aplikace volá rozšíření našeho rozhraní pomocí
vlastnosti
AppServer své připojovací komponenty. Více informací
nalezneme ve
Volání rozhraní serveru.
Poskytování z a
řešení na datové množině
Komponenta poskytovatele získává svá data od datové množiny
specifikované vlastností DataSet. Implicitně, ale když komponenta
TProvider
aplikuje aktualizace a řeší aktualizační chyby, pak komunikuje přímo s
databázovým serverem pomocí dynamicky generovaných příkazů SQL. Tato možnost
má výhodu v tom, že naše serverová aplikace nemusí slučovat aktualizace
dvakrát (poprvé na datovou množinu a pak na vzdálený server). Nicméně,
když naše komponenta poskytovatele aplikuje aktualizace a řeší problémy
pomocí SQL, pak vlastnost DataSet musí specifikovat datovou množinu
podporující BDE.
Můžeme použít komponentu poskytovatele, která aplikuje
aktualizace a řeší chyby přímo na datové množině aplikačního serveru. Pomocí
této možnosti můžeme použít klientskou datovou množinu nebo přizpůsobenou
datovou množinu na našem aplikačním serveru. Tím můžeme reprezentovat data,
která nemohou být zpřístupněna žádným ovladačem BDE. K řešení na datové
množině, která nepodporuje BDE použijeme komponentu TDataSetProvider.
Můžeme také řešit na datovou množinu podporující BDE místo dynamicky generovaných
příkazů SQL nastavením vlastnosti ResolveToDataSet naší komponenty
TProvider
na true.
Poznámka: Na rozdíl od TProvider, TDataSetProvider
nezávisí na BDE. Když použijeme tuto komponentu, pak naše serverová aplikace
nemusí obsahovat BDE. To může zjednodušit šíření.
Správa transakcí
ve více vrstvových aplikacích
Když klientská aplikace aplikuje aktualizace na aplikační
server, pak komponenta poskytovatele automatizuje proces aplikování aktualizací
a řešení konfliktů v transakci. Tato transakce je zapsána, pokud počet
problémových záznamů nepřekračuje počet MaxErrors specifikovaný
jako parametr metody
ApplyUpdates. Jinak je transakce zrušena.
Dále můžeme přidat podporu transakcí k naší serverové
aplikaci přidáním komponenty databáze nebo pomocí průchozího SQL. Pracuje
to stejným způsobem jako používáme pro správu transakcí ve dvou vrstvových
aplikacích. S problematikou řízení transakcí jsme se již seznámili.
Pokud používáme MTS, pak můžeme rozšířit naši podporu
transakcí na MTS transakce. MTS transakce mohou zahrnovat libovolnou logiku
na našem aplikačním serveru. Dále, protože také podporuje dvoufázový commit,
MTS transakce se mohou týkat více databází.
Varování: Dvoufázový commit je plně podporován
pouze na Oracle 7 a MS-SQL databázích. Jestliže naše transakce se týká
více databází, a některé z nich jsou jiné než Oracle 7 nebo MS-SQL, pak
naše spuštěná transakce může riskovat pouze částečný úspěch. V libovolné
jedné databázi, nicméně, vždy máme podporu transakcí.
K použití MTS transakcí, rozšíříme rozhraní aplikačního
serveru k vložení metod jejich volání zaobalují transakci. Když konfigurujeme
vzdálený datový modul MTS, pak zadáme, že musíme pracovat v transakcích.
Když klient volá metodu rozhraní našeho aplikačního serveru, pak je automaticky
vložena do transakce. Všechna klientská volání našeho aplikačního serveru
jsou tedy vkládány do transakce dokud neurčíme, že transakce je kompletní.
Tato volání mohou být všechna úspěšná nebo jsou zrušena.
Poznámka: Nesmíme kombinovat transakce MTS
s explicitními transakcemi vytvořenými komponentou databáze nebo pomocí
průchozího SQL.
Podporování vzájemného
vztahu Master-detail
Mezi klientskými datovými množinami v naší klientské aplikaci
můžeme vytvořit vzájemný vztah Master-detail a to stejným způsobem jako
v jedno nebo dvou vrstvové aplikaci. Tato možnost má ale dva hlavní nedostatky:
-
Detailní tabulka musí získávat a ukládat všechny své záznamy
z aplikačního serveru pouze s použitím jedné detailní množiny.
-
Je velmi obtížné aplikovat aktualizace, protože klientská
datová množina aplikuje aktualizace na úrovni datových množin a aktualizace
Master-detail se může týkat více databází.
Ve více vrstvových aplikacích můžeme zabránit těmto problémům
použitím vnořených tabulek k reprezentaci vzájemného vztahu Master-detail.
Provedeme to tak, že nastavíme vzájemný vztah Master-detail mezi tabulkami
na aplikačním serveru. Pak nastavíme vlastnost DataSet naší komponenty
poskytovatele na tabulku Master. Když klient volá metodu GetRecord
poskytovatele, pak je automaticky vložena detailní datová množina jako
položka DataSet do záznamu datového paketu. Když klient volá ApplyUpdates
poskytovatele, pak aplikování aktualizací proběhne správně.
Podporování
beze stavových vzdálených datových modulů
Když používáme transakce a aktivaci just-in-time pro MTS,
pak nemůžeme používat rozhraní IProveder. Je to z důvodu, že:
-
Rozhraní IProvider zjišťuje a nastavuje stavové informace.
Např. když nastavíme parametry nebo požadujeme data pomocí inkrementálního
získávání, pak poskytovatel na aplikačním serveru si musí "pamatovat" předchozí
volání
IProvider, a tak může poskytnou očekávaná data.
-
Pod MTS, když aplikační server je deaktivován, pak vlastnost
Provider
klientské datové množiny se stane chybnou.
Můžeme stále používat poskytovatele na aplikačním serveru.
Abychom to mohli provést, musíme zapsat své vlastní beze stavové rozhraní.
Pokud potřebujeme vložit stavovou informaci, pak musíme přidat parametr
k volání rozhraní nebo vložíme stavovou informaci do našich datových paketů
jako přizpůsobenou informaci.
Poznámka: Pod MTS, každá metoda našeho rozhraní
musí volat metodu SetComplete objektu IObjectContext k oznámení
dokončení. To slouží k dokončení transakce a aplikační server může být
deaktivován.
Pro získávání záznamů od poskytovatele, rozšíříme rozhraní
aplikačního serveru, k vložení volání k získání záznamů od specifického
poskytovatele na aplikačním serveru. Tato metoda pracuje nějak jako následující
metoda implementující třídy MTS:
OleVariant__fastcallTMyRemoteDataModuleImpl::GetCustomerRecords
(bool
MetaData, int &RecsOut)
{
OleVariant Result = NULL;
try
{
if (MetaData)
Result = CustomerProvider->GetRecords(0,
RecsOut);
else
Result = CustomerProvider->GetRecords(-1,
RecsOut);
}
catch (...)
{
ObjectContext.SetAbort();
return Result;
}
ObjectContext.SetComplete();
return Result;
}
Na klientské straně, můžeme přiřadit vrácenou hodnotu
touto metodou přímo vlastnosti Data klientské datové množině:
ClientDataSet1->Data =
MyConnectionComponent->AppServer.GetCustomerRecords(False,
RecsOut);
Pro aplikování aktualizací, přidáme metodu k rozhraní
aplikačního serveru takto:
OleVariant__fastcallTMyRemoteDataModuleImpl::ApplyCustomerUpdates
(OleVariant Delta,
int MaxErrors, int &ErrorCount)
{
OleVariant Result = NULL;
try
{
OleVariant Result =
CustomerProvider->ApplyUpdates(Delta, MaxErrors, ErrorCount);
}
catch (...)
{
ObjectContext.SetAbort();
return Result;
}
ObjectContext.SetComplete();
return Result;
}
Na straně klienta, místo volání metody ApplyUpdates
klientské datové množiny, musíme volat tuto metodu rozhraní:
ClientDataSet1->CheckBrowseMode();
if (ClientDataSet1->ChangeCount > 0)
{
IMyRemotedataModuleDisp TempInterface(LPDISPATCH(MyConnection->AppServer));
ClientDataSet1->Reconcile(
TempInterface->ApplyCustomerUpdates(ClientDataSet1->Delta,
ClientDataSet1->MaxErrors, ErrCount);
}
Distribuovatelné
klientské aplikace jako ovladače ActiveX
Architektura distribuovaných databází C++ Builderu může být
kombinovaná se službami ActiveX k distribuování klientských aplikací jako
ovladačů ActiveX.
Když distribuujeme naší klientskou aplikaci jako ActiveX,
pak vytvoříme aplikační server jako pro libovolnou jinou více vrstvovou
aplikaci. Jediné omezení je to, že jako komunikační protokol musíme používat
DCOM nebo sokety, protože nemůžeme počítat s tím, že na klientských počítačích
je instalováno běhové prostředí OLEnterprise.
Když vytváříme klientskou aplikaci, pak musíme použít
jako její základ
Active Form místo normálního formuláře. Viz Vytváření
Active Form pro klientskou aplikaci.
Když již máme vytvořenou a šíříme klientskou aplikaci,
pak ji můžeme zpřístupnit z Webovského prohlížeče podporujícího ActiveX
a jiném počítači. Abychom z Webovského prohlížeče mohli úspěšně získat
klientskou aplikaci, Webovský server musí být spuštěn na počítači, který
má klientskou aplikaci.
Pokud klientská aplikace používá pro komunikaci klientské
aplikace a aplikačního serveru DCOM, pak počítač s Webovským prohlížečem
musí umožňovat práci s DCOM.
Vytváření Active
Form pro klientskou aplikaci
-
Protože klientská aplikace bude šířena jako ovladač ActiveX,
musíme mít Webovský server spuštěn na stejném počítači jako klientskou
aplikaci. Musíme používat server typu Netscape server nebo IIS Microsoft,
nebo můžeme zapsat svůj vlastní Webovský server používající komponenty
soketů.
-
Vytvoříme klientskou aplikaci obdobně jako libovolnou jinou
klientskou aplikaci, pouze začneme volbou File | New | Active Form
místo normálního zahájení projektu.
-
Pokud naše klientská aplikace používá datový modul, přidáme
volání k explicitně vytvořenému datovému modelu v inicializaci aktivního
formuláře.
-
Když naši klientskou aplikaci dokončíme, přeložíme projet
a zvolíme Project | Web Deployment Options. V zobrazeném dialogovém
okně musíme:
-
Na stránce Project specifikovat cílový adresář, URL
pro cílový adresář a HTML adresář. Obvykle, cílový a HTML adresáře jsou
stejné jako projektový adresář pro Webovský server. Cílové URL je obvykle
jméno počítače serveru, který je specifikován v nastavení Windows Network
| DNS.
-
Na stránce Additional Files vložíme dbclient.dll
a
stdvcl32.dll
s naší klientskou aplikací.
-
Na konec, vybereme Project | WebDeploy k šíření klientské
aplikace jako aktivního formuláře.
Libovolný Webovský prohlížeč, který může spustit aktivní
formulář, může spustit naší klientskou aplikaci specifikací souboru HTML
vytvořeným při šíření klientské aplikace. Tento HTML soubor má stejné jméno
jako projekt naší klientské aplikace a je umístěn v adresáři specifikovaném
jako cílový adresář.
|
20. Vytváření více vrstvových
aplikací
|