Você está na página 1de 106

CURSO POR GUINTER PAULI CLUBE DELPHI

Curso de dbExpress e DataSnap


Parte I - Apresenta!o
A idia de construir este curso partiu na boa aceitao que tivemos em lanar o curso em 20
partes sobre acesso a dados no Delphi for .NET, com ADO.NET (Active Data Objects) e BDP
(Borland Data Provider), que o leitor pde acompanhar nos ltimos meses aqui na
ClubeDelphi. O curso tambm est disponvel na forma de E-Book. A partir deste artigo, damos
incio um curso de acesso a dados usando o Delphi Win32, voltado para o ambiente
client/server e multitier. Acredito que muitos de vocs desenvolvedores j possuem pelo
menos uma aplicao desse tipo em produo. Que tal conhecer alguns recursos interessantes
para aplicar rapidamente em suas aplicaes, fazendo otimizaes e garantindo performance?

Este o primeiro de uma srie de 30 artigos que mostrar tcnicas avanadas de uso das
principais tecnologias de acesso a dados do Delphi Win32: dbExpress e DataSnap. Ao longo
deste curso, voc conhecer importantes caractersticas e recursos de cada um dos
componentes utilizados. Em especial, pretendo apresentar inmeras dicas e segredos de
utilizao de um componente que considero ser o melhor j criado pela Borland: o
ClientDataSet.
Pretendo criar um curso bastante dinmico: gostaria de elaborar tpicos de acordo com a
necessidade e idias de vocs, amigos leitores. Escrevam e sugiram tpicos que gostariam que
fossem contemplados aqui no curso. Alm disso, no final, pretendo colocar um grande
documento de FAQs com perguntas e respostas, enviadas pelos leitores que faro o curso.

Para criar os exemplos aqui demonstrados, voc pode utilizar o Delphi 6, 7 ou o Delphi 2005.
Como banco de dados, utilizarei o Interbase 7.5, mas voc pode utilizar qualquer outro banco
de sua preferncia, como Firebird, SQL Server, Oracle, MySQL, todos os cdigos apresentados
funcionam perfeitamente com qualquer um desses SGDBs.
Desejo um bom curso a todos, sugestes sero bem-vindas. Um abrao a todos e desejo
sucesso nos projetos de banco de dados com Delphi

Do"n#oad
Voc pode fazer download de todos os exemplos deste curso a partir do endereo
cc.borland.com/cc/ccweb.exe/author?authorid=222668

dbExpress$ DataSnap e C#%entDataSet& t'(n%(as a)anadas
Para mais informaes sobre acesso a dados no Delphi e tcnicas avanadas, sugiro a leitura
do meu livro, "Delphi: Programao para Banco de Dados e Web, como apoio para o
aprendizado das tecnologias. Na obra mostro vrias tcnicas introdutrios e avanadas de
desenvolvimento com ClientDataSet, dbExpress e DataSnap (multicamadas, incluindo SOAP e
COM+).
Parte II - Con*e(endo os (o+ponentes
Nesta primeira parte do curso de dbExpress, vamos conhecer os principais componentes da
paleta dbExpress e DataSnap do Delphi, vendo suas funcionalidades e objetivos.
Co+ponentes do dbExpress e DataSnap
Os componentes dbExpress e DataSnap podem ser vistos na figura a seguir:


Nesta primeira parte do curso, vamos conhecer brevemente cada um dos componentes
envolvidos em aplicaes dbExpress. Nos artigos seguintes, vamos detalhar cada um deles.
,%s!o -era# dos (o+ponentes
SQLConnection

Esse componente responsvel pela conexo com o banco de dados.

TSQLDataset

Componente responsvel por obter dados de um servidor SQL usando cursores unidirecionais.
Tambm pode executar uma procedure no servidor. Ele pode atuar tanto como uma Query,
uma Table ou uma StoredProc.

TSQLQuery

Componente que fornece uma maneira de executar um comando SQL usando uma conexo
dbExpress.

TSQLStoredProc

Usado para executar um procedure remoto no servidor SQL.

TSQLTable

Usado para representar uma tabela acessada atravs de uma conexo dbExpress.

TSQLMonitor

Monitora as trocas de mensagens e instrues SQL feitas entre uma aplicao cliente e um
servidor SQL.

TClientDataset

Utilize TClientDataset para fornecer um mecanismo de cache para os Datasets unidirecionais.
Por ser conectado a um TDatasetProvider, os dados podero ser capturados de um servidor de
aplicao.

TDatasetProvider

TDatatasetProvider prov dados de um Dataset e aplica as atualizaes feitas em um
TClientDataset (delta) no servidor de dados. Ele responsvel por criar os pacotes de dados
que trafegam entre uma aplicao cliente e um servidor de aplicao em uma arquitetura
multicamadas. Ele pode se comunicar com um servidor de aplicao por meio da interface
IAppServer.

SimpleDataSet

Esse componente o conjunto de quatro componentes, e facilita a conexo rpida com banco de
dados, indicado para criao de aplicaes simples e prottipos.



DCOMConnection

Efetua uma conexo com um servidor de aplicao DataSnap, do tipo DCOM, MTS ou COM+

SocketConnection

Efetua uma conexo com um servidor de aplicao DataSnap, do tipo Sockets

WebConnection

Efetua uma conexo com um servidor de aplicao DataSnap, usando o protocolo HTTP. Seu
uso no mais aconselhado, sendo prefervel o uso de um SOAPConnection para conexes
DataSnap atravs da Web / HTTP.

SimpleObjectBroker

Permite criar um mecanismo simples de balanceamento de carga em servidores DataSnap. Por
exemplo, ele pode despachar uma conexo cliente para um segundo servidor de aplicao se o
primeiro servidor estiver congestionado.

SharedConnection

Permite acesso a um DataModule "filho em um servidor de aplicao com mltiplos mdulos.

LocalConnection

Permite simular um ambiente multicamadas em um ambiente 2-tier, atravs de um mdulo
compartilhado (DataModule). Com isso, ClientDataSets podem "enxergar Providers em outras
units, como se fosse uma camada fsica.

ConnectionBroker

Este componente tem por finalidade abstrair (isolar) o tipo de conexo para os ClientDatasets.
Se algum dia for preciso mudar o tipo de servidor, no seria necessrio reconfigurar os
ClientDatasets caso se mudasse DCOMConnection para SOAPConnection, por exemplo.
Parte III - Ar.u%tetura
Nesta parte do curso, vamos examinar detalhes sobre a arquitetura de aplicaes dbExpress
que utilizam os componentes bsicos, tpicos de uma aplicao client/server ou multicamadas:
SQLConnection, SQLQuery, DataSetProvider e ClientDataSet . Veremos tambm as vantagens
em se utilizar uma aplicao multicamadas.
Ar.u%tetura
A figura a seguir mostra as partes envolvidas em um sistema multicamadas. Na primeira
camada, temos o chamado servidor de dados. Nele est localizado o banco de dados
propriamente dito. O banco de dados pode ser Oracle, DB2, MySQL, Interbase ou qualquer
outro suportado pelo dbExpress. Como a conexo feita via TCP/IP, voc pode usar um SO
diferente do Windows, como Linux.
A camada intermediria, conhecida como servidor de aplicao, contm o DataModule
(tambm conhecido como RemoteDataModule ) responsvel pelo acesso a dados. Nessa
camada se encontram os componentes dbExpress, como SQLConnection, SQLQuery,
SQLDataSet e os DataSetProviders . Nessa camada voc tambm vai incluir as chamadas
regras de negcio . Business Rules so regras impostas sobre dados, que no sero mais
processadas no servidor SQL. Com isso, seu sistema consegue centralizar as regras sem
depender do tipo de banco utilizado.
E finalmente, a camada cliente responsvel apenas pela apresentao dos dados. Contm
basicamente regras de tratamento de tela e interface. Por isso, so chamadas de thin-clients
(clientes leves).

A seguir, vamos examinar as vantagens de se desenvolver aplicaes multicamadas com
DataSnap e dbExpress.
Vantagens de uma soluo Multitier
/odu#ar%0a!o da ap#%(a!o e+ 1 (a+adas
Quando desenvolvemos uma aplicao Multicamadas com DataSnap, separamos a lgica de
negcio e regras de acesso a banco de dados das regras de interface de usurio. Dessa forma,
vrios clientes podem compartilhar as mesmas regras, que ficam encapsuladas em uma
camada de acesso comum. Observe que em uma aplicao 2 camadas h geralmente uma
redundncia de regra de negcio nas estaes clientes, e uma simples mudana nessa regra
requer uma nova distribuio da aplicao. Suponha que voc esteja fazendo um simples
cadastro de clientes, com interface tradicional baseada em formulrios. Ento voc inclui no
DataModule da aplicao uma determinada validao de dados. Se voc agora precisar
construir uma verso On-Line deste cadastro, atravs de um formulrio que poder ser aberto
em um browser Web, ento ser necessrio recodificar a regra anterior. Neste caso, uma
camada lgica intermediria poderia centralizar todas as regras e atender tanto aplicaes
clientes baseadas em formulrios, quanto aplicaes baseadas em browser.
C#%entes Le)es 2T*%n-C#%ents3
Uma aplicao cliente de uma arquitetura Multitier basicamente contm cdigo de interface.
Todo o processamento das solicitaes de dados ao servidor SQL so feitas na camada
intermediria, de forma que um cliente nunca se comunica diretamente com o banco de dados.
Dessa forma, uma aplicao cliente DataSnap muito leve, pequena, e de configurao quase
zero. Por este motivo este tipo de cliente tambm conhecido como Thin-Client ou cliente leve
(magro).
E(ono+%a de #%(enas de a(esso a Ban(o de dados
Quando trabalhamos com aplicaes 2 camadas, cada cliente de nossa aplicao se comunica
diretamente com o banco de dados, por meio de um SQL Client. Este SQL Client um conjunto
de bibliotecas (que muitas vezes ocupam vrios MB de espao em disco) que possibilita um
terminal da rede trocar comandos SQL com um servidor de dados SQL. Voc precisa instalar
estas bibliotecas em cada estao que acesse o servidor. Quando o driver do cliente troca de
verso, voc precisa atualizar todas as mquinas da rede (isso sem falar da sua aplicao).
Um outro aspecto nada interessante que geralmente as empresas fabricantes de banco de
dados cobram licenas extras pela instalao destas bibliotecas clientes. Agora se voc
construir seu sistema baseado em uma arquitetura Multitier, as bibliotecas do SQL Client (seja
qual for o banco) devero ser instaladas somente na camada intermediria (camada de acesso
a dados), poupando conexes no servidor e economizando licenas. Todos os clientes dessa
forma compartilham uma nica conexo com o banco de dados SQL. Se seu aplicativo utiliza
ainda o BDE como tecnologia Borland de acesso a dados, estes drivers tambm sero
necessrio somente na aplicao intermediria, e no mais no cliente final. O mesmo vale para
os drivers de acesso a dados do dbExpress.
Es(a#ab%#%dade
Um software bem desenvolvido sobre uma arquitetura Multicamadas extremamente
escalvel. Isto , a medida que mais clientes comeam a conectar no servidor de aplicao e
utilizar seus recursos, no h uma perda de desempenho e performance, como acontece em
aplicaes 2 camadas tradicionais.
Independ4n(%a de L%n-ua-e+
Uma camada de negcio construda sobre um padro COM, por exemplo, pode ser acessada
por clientes escritos em diversas linguagens de programao que dem suporte ao COM. Essa
comunicao possvel devido ao mecanismo conhecido como Interfaces. Um servidor COM
(escrito em Delphi, por exemplo) pode ser acessado de um cliente escrito em VB, ASP, C, etc.
Independ4n(%a de Ban(o de Dados
Como uma aplicao cliente Datasnap no se comunica diretamente com o banco de dados,
este no precisa nem mesmo saber qual o banco de dados utilizado. possvel migrar de
Banco de Dados, por exemplo, de Interbase para Oracle, sem mesmo recompilar as aplicaes
clientes (e as vezes nem mesmo a camada intermediria).
Ba#an(ea+ento de Car-a
Um servidor de aplicao pode ser configurado para automaticamente distribuir as conexes
clientes para outros servidores de aplicao, tornando a arquitetura ainda mais escalvel. Isso
facilmente alcanado apenas se usando o componente SimpleObjectBroker.
5un(%ona+ento de u+a ap#%(a!o dbExpress
A figura a seguir mostra uma aplicao tpica dbExpress, e todos os passos envolvidos desde a
requisio de dados at a atualizaes das alteraes no servidor. Todos os procedimentos a
seguir acontecem imediatamente aps voc dar um Open em um ClientDataSet . Inclu
tambm a especificao das etapas de atualizao.

Conexo: o componente SQLConnection estabelece uma conexo TCP/IP com o servidor SQL;

Abertura de um cursor de dados: um SQLDataSet ou SQLQuery efetua uma consulta ( select )
no banco de dados, por meio de um SQLConnection . O servidor SQL abre ento um cursor de
dados, alocando recursos;

DataSetProvider : aps o cursor ser aberto, o DataSetProvider varre o cursor de dados (uma
operao while not eof ) montando um pacote de dados ( DataPacket ).

Providing : o DataSetProvider fecha o cursor de dados, liberando recursos, e envia os dados
obtidos em forma de DataPacket para o ClientDataSet , em uma operao chamada Providing .

Cache : o ClientDataSet armazena os dados em cache, local, no sendo necessria nenhuma
conexo com o banco de dados;

ApplyUpdates - o ClientDataSet envia as atualizaes de volta ao DataSetProvider , em um
pacote de dados conhecido como Delta ;

Resolving - para cada registro alterado, o DataSetProvider tenta atualizar o respectivo registro
no banco de dados, gerando automaticamente instrues de atualizao como update, delete e
insert .

Reconcile - eventuais erros ocorridos durante o Resolving so devolvidos ao ClientDataSet ,
para que sejam tomadas solues, em um processo chamado Reconcile .
Parte I, S6LConne(t%on (r%ando (onex7es
Nesta parte do curso, vamos conhecer em detalhes o componente SQLConnection e criar nossa
primeira conexo dbExpress.
A (#asse TS6LConne(t%on
A classe TSQLConnection representa uma conexo dbExpress. Um SQLConnection faz uso de
um driver para conectar um servidor de banco de dados. Os atuais bancos suportados so:
DB2
MySQL
SQL Server
Informix
Oracle
InterBase

O dbExpress no suporta bancos locais, como Paradox e DBase. Isso porque o dbExpress nada
mais que uma "casca fina sobre a API do banco de dados SQL. Como Paradox e DBase no
so servidores SQL (SDBDs), no so suportados pelo dbExpress.
Os driver e conexes so definidos em dois arquivos de configurao. O primeiro,
dbxdrivers.ini em Windows ou os dbxdrivers em Linux, lista os drivers instalados e as
bibliotecas (DLLs ou shared objects no Linux (so)) requeridos pela conexo. O segundo,
dbxconnections.ini, em Windows ou os dbxconnections em Linux, lista as configuraes da
conexo. Cada configurao representa um conjunto de parmetros de componentes
TSQLConnection e descreve uma conexo com um banco de dados. Para criar uma
configurao, basta dar um duplo clique em um componente TSQLConnection e usar editor
para criar a conexo.
S6LConne(t%on - Pr%n(%pa%s Propr%edades
ActiveStatements
Nmero de comandos ativos sendo executados no banco de dados

AutoClone
Especifica se o componente automaticamente clona conexes com o banco de dados quando
for necessrio

Connected
Indica se a conexo est ativa

ConnectionName
Nome da conexo no arquivo de configurao

ConnectionState
Indica o corrente estado da conexo

DataSets
Lista todos os DataSets ativos da conexo

DriverName
Indica o nome do driver associado conexo

GetDriverFunc
Indica a funo exportada na DLL do driver

InTransaction
Se uma transao est em progresso

KeepConnection
Indica se a conexo deve ficar ativa se no existirem DataSets abertos

LibraryName
Nome da DLL do driver dbExpress

LoadParamsOnConnect
Indica se o componente deve ler as configuraes dinamicamente a partir do
dbxconnections.ini

LocaleCode
Indica se a ordenao em DataSets deve ser com base na localizao

MaxStmtsPerConn
Indica o nmero mximo de comandos ativos por conexo

MetaData
Permite acesso aos metadados do banco de dados

MultipleTransactionsSupported
Indica se o banco de dados suporta mltiplas transaes

Params
Lista os parmetros de conexo

ParamsLoaded
Indica se os parmetros foram lidos do dbxconnections.ini

SQLConnection
Acesso ao objeto interno do driver dbExpress que representa a conexo

SQLHourGlass
Indica se o cursor de tela (SQL) deve ser usado durante processamentos

TableScope
Indica quais tipos de tabelas devem ser retornadas em operaes de metadados

TransactionsSupported
Indica se o banco de dados suporta transaes

VendorLib
Indica o nome da biblioteca cliente (DLL) do banco de dados
S6LConne(t%on - Pr%n(%pa%s /'todos
CloneConnection
Retorna uma cpia do objeto de conexo

CloseDataSets
Fecha todos os DataSets associados conexo

Commit
Efetua um Commit em uma transao

Create
Cria uma instncia da classe TSQLConnection

Destroy
Destri a instncia do objeto

Execute
Executa um comando SQL no banco de dados

ExecuteDirect
Executa um comando SQL no banco de dados, que no possua parmetros

GetDefaultSchemaName
Retorna o default schema do objeto do banco de dados

GetFieldNames
Obtm a lista de campos de uma tabela, em um TStrings

GetIndexNames
Obtm a lista de ndices de uma tabela, em um TStrings

GetLoginUsername
Retorna o nome do usurio logado no BD

GetPackageNames
Obtm a lista de packages do BD, em um TStrings

GetProcedureNames
Obtm a lista de stored procedures do BD, em um TStrings

GetProcedureParams
Obtm a lista de parmetros de stored procedures do BD, em um TStrings

GetSchemaNames
Obtm o nome de todos os objetos do BD, em um TStrings

GetTableNames
Obtm a lista de tabelas do BD, em um TStrings

LoadParamsFromIniFile
Carrega os parmetros de conexo a partir de um arquivo INI

Rollback
Efetua um RollBack em uma transao

SetTraceCallbackEvent
Define uma funo de callback que chamada para cada comando executado no servidor

StartTransaction
Inicia uma transao

Close
Fecha a conexo

Open
Abre a conexo
S6LConne(t%on - Pr%n(%pa%s E)entos
OnLogin
Permite definir parmetros de login (username e senha).

TraceCallbackEvent
Permite acesso a uma funo de callback que chamada para cada comando executado no
servidor

AfterConnect
Disparado aps a conexo ser estabelecida

BeforeConnect
Disparado antes da conexo ser estabelecida

AfterDisconnect
Disparado aps a conexo ser fechada

BeforeDisconnect
Disparado antes da conexo ser fechada
Cr%ando u+a (onex!o
muito simples criar uma conexo dbExpress. Pressupondo que voc j tenha o Interbase
rodando e previamente configurando (neste curso vou usar o IB 7.5), basta colocar um
SQLConnection no form, dar um duplo clique sobre ele e acessar o editor de conexes:

No editor de conexes do dbExpress, clique no cone +. Escolha o driver do banco desejado e
d um nome para a conexo:

Informe no parmetro DataBase o caminho do banco de dados:

Nota& O parmetro Database utilizado de diferentes formas, dependendo do driver. Para
conexes IB / FB, preciso especificar o nome do host (servidor) juntamente com o caminho
do banco, separados por ":. errado tentar acessar o servidor usando algo do tipo
"\\servidor\c$\caminho\db.gdb. Nesse caso, o servidor seria a mquina local, mas acessando
um arquivo em outra mquina usando compartilhamento de rede.

Para o SQL Server, por exemplo, o nome do servidor e do banco so indicados em parmetros
distintos (HostName e Database). Nesse caso, Database no o caminho fsico do banco no
disco, mas o nome registrado no Enterprise Manager. Para o DB2, o Database deve indicar o
Alias configurado no DB2 Client, que contm outras informaes de acesso, como o endereo
do servidor, porta etc. Procedimento semelhante tambm feito para o Oracle.
Essa configurao fica salva no arquivo dbxconnections.ini
dbx(onne(t%ons8%n%
O dbExpress e o BDE so bastante semelhantes com relao aos parmetros utilizados em
uma conexo. Como voc deve lembrar, o BDE guardava informaes sobre os aliases em um
arquivo chamado idapi32.cfg, localizado normalmente em c:\Arquivos de Programas\Arquivos
Comuns\Borland Shared\BDE. Esse arquivo no era manipulado diretamente, e sim utilizando-
se o BDE Administrator a partir do Painel de Controle.

Com isso, ficava muito simples alterar dinamicamente um parmetro de conexo, como o
caminho do banco ou endereo do servidor, pois essas informaes ficavam externas
aplicao. No era preciso recompilar nada caso fosse necessrio fazer alguma modificao nos
parmetros de acesso. Tambm era possvel utilizar um componente Database. Em
compensao, o BDE uma "camada pesada de acesso a servidores SQL. Foi feito para o
mundo duas camadas e possui um mecanismo de cache rudimentar. Freqentemente o
desenvolvedor sentia-se obrigado a instalar quase 18 MB de DLLs para acesso a um BD.

Ao contrrio, o dbExpress um engine leve de acesso, baseado na implementao de
interfaces que acessam diretamente o driver cliente do BD, dispensado a instalao de
bibliotecas adicionais. Tudo o que voc precisa distribuir a DLL indicada na propriedade
LibraryName do SQLConnection, cujo tamanho varia entre 90 kb e 200 kb, dependendo do
driver. Tambm necessrio distribuir a biblioteca Midas.dll, que na atual verso possui
somente cerca de 290 Kb.

Semelhante ao BDE, as informaes sobre as conexes criadas no dbExpress ficam em um
arquivo de configurao, chamado dbxconnections.ini, localizado normalmente em c:\Arquivos
de Programas\Arquivos Comuns\Borland Shared\dbExpress. Abra esse arquivo e veja que ele
contm uma sesso chamada "DB_IB, que define os parmetros da conexo que criamos no
Delphi. Veja um trecho do arquivo a seguir (esses parmetros so os mesmos que esto
atualmente na propriedade Params do SQLConnection):

[DB_IB]
DriverName=Interbase
Database=localhost:c:\caminho\db.gdb
User_Name=sysdba
Password=masterey
!"#Dialect=$
...

O arquivo dbxconnections.ini utilizado, at agora, apenas pela IDE do Delphi. Repare que
cada conexo tem um parmetro chamado DriverName. O Delphi utiliza esse valor para
configurar algumas propriedades do SQLConnection que so especficas do driver utilizado.

Por exemplo, se o DriverName for Interbase, as propriedades GetDriverFunc, LibraryName e
VendorLib tero os valores getSQLDriverINTERBASE, dbexpint.dll e gds32.dll, respectivamente.
Esses valores mudam para o DB2, Oracle, SQL Server etc. Essas configuraes so obtidas
atravs de um segundo arquivo de configurao, chamado dbxdrivers.ini.

D%(a& Para mais informaes sobre os arquivos de inicializao do dbExpress, consulte os
tpicos "dbxconnections.ini e "dbxdrivers.ini na ajuda do Delphi.
Testando a (onex!o
Pronto, agora j podemos testar a conexo! Para isso, coloquei um Button no form e digitei:

procedure &'orm(.B)tton(*lic+!ender: &,b-ect./
begin
try
try
!"#*onnection(.,0en+./
!how1essage+2*one34o 5eita com s)cesso62./
except
!how1essage+27rro ao conectar2./
end/
finally
if !"#*onnection(.*onnected then
!"#*onnection(.*lose+./
end/
end/

Lembre-se de definir o LoginPrompt como False. Execute e teste a aplicao.

Parte , Introdu!o ao uso de DataSets Un%d%re(%ona%s
Neste artigo teremos uma pequena introduo ao conceito e uso de DataSets Unidirecionais do
dbExpress, atravs dos componentes TSQLDataSet, TSQLTable e TSQLQuery.
O .ue s!o DataSets un%d%re(%ona%s
A principal funo dos Datasets unidirecionais recuperar dados de um banco SQL. Eles no
mantm nenhum buffer na memria ou criam qualquer tipo de cache, o que era comum em
Datasets bidirecionais, como os usados no BDE. Por serem implementados desta forma,
Datasets unidirecionais so bem mais rpidos, exigem pouco processamento e utilizam o
mnimo de recursos da mquina, diferentemente dos Datasets TQuery e TTable baseados no
BDE. Em Datasets unidirecionais no permitido: edio, campos lookup, filtros e navegao
com prior e last. Ao tentar realizar operaes no permitidas sobre um Dataset unidirecional,
uma exceo do tipo EdataBaseError levantada com a mensagem : "Operation not allowed
on a unidirectional dataset.

At o BDE, quando o usurio "rolava o cursor de dados na aplicao cliente, por exemplo,
usando um DBNavigator, havia uma troca de mensagens com o "kernel do BDE, que precisava
manter o cursor alocado no servidor de banco de dados para permitir a navegao bidirecional.
Isso poderia comprometer a performance de solues baseadas nessa arquitetura, visto que
para atender n cliente simultaneamente, o BD precisava manter ativo os cursores alocados no
servidor.

Com o dbExpress, o tempo de transao e vida til do cursor de dados no servidor bastante
pequeno, devido ao uso de DataSetProviders e ClientDataSets. Quando damos um Open em
um ClientDataSet, enviada uma solicitao para o DataSetProvider, que abre o Dataset
unidirecional associado. O DataSetProvider "varre ento o cursor aberto pela consulta e
"empacota os dados em um DataPacket, que alocado na memria do ClientDataSet. Nesse
momento, o usurio pode trabalhar tranquilamente nos dados em tela, e o dbExpress pode
fechar a consulta (cursor) que no ficar mais ativa (diferente do BDE). Por esse motivo,
aplicaes dbExpress e DataSnap so extremamente rpidas.
DataSets do dbExpress
Os componentes da guia dbExpress possuem os mesmos ancestrais dos componentes
baseados no BDE. Isso significa que muita coisa ser semelhante ao migrar de BDE para DBX,
graas aos recursos de abstrao e polimorfismo, principalmente das classes TDataset, TField e
TCustomConnection. Essas classes formam a base para os vrios componentes de acesso a
dados, campos e conexo a bancos de dados disponveis no Delphi.

Os DataSets do pacote dbExpress so chamados unidirecionais. Basicamente, este tipo de
Dataset tem a funo de retornar dados de um servidor SQL, mas no de manipul-los
(buffering). Para cada banco de dados que vamos acessar, o dbExpress fornece um driver
especfico que deve ser distribudo juntamente com a aplicao. Todos os TDatsets usados no
dbExpress herdam de TCustomSQLDataset. Todas as classes do dbExpress esto declaradas na
unit SqlExpr.pas.
Exe+p#o usando so+ente DataSets Un%d%re(%ona%s
possvel utilizar DataSets Unidirecionais diretamente, sem usar um ClientDataSet. Essa
tcnica bastante utilizada, por exemplo, para confeco de relatrios. Ou seja, lemos um
registro, fazemos alguma coisa com ele, e navegamos para o prximo, sem armazenar nada
em memria.
exatamente isso que mostrarei neste exemplo. Inicie uma nova aplicao VCL no Delphi.

Coloque um SQLConnection e um SQLDataSet no formulrio.

No SQLConnection, configure uma conexo para o banco Employee do Interbase ou do Firebird
(j discutimos conexes anteriormente, de forma que no vou entrar em detalhes aqui).

Aponte o SQLDataSet para o SQLConnection, atravs da propriedade Connection e em
CommandText digite

select 8 5rom c)stomer


Coloque um DataSource e aponte sua propriedade DataSet para o SQLDataSet. Neste
momento, voc dever receber a seguinte mensagem de erro:


Isso acontece pois um DBGrid exige navegao bidirecional no cursor de dados, o que no
suportado pelo dbExpress. Para isso, voc precisaria de um ClientDataSet (no usaremos ainda
neste exemplo). Retire ento o DBGrid e coloque um ListView.

No evento OnShow do formulrio digite:

procedure &'orm(.'orm!how+!ender: &,b-ect./
var
it: &#istItem/
i: integer/
begin
#ist9iew(.9iew!tyle := vs:e0ort/
!"#Data!et(.,0en/
try
for i := ; to 0red+!"#Data!et(.'ields.*o)nt. do
with #ist9iew(.*ol)mns.<dd do
*a0tion := !"#Data!et(.'ields[i].'ieldName/
while not !"#Data!et(.7o5 do
begin
it := #ist9iew(.Items.<dd/
it.*a0tion := !"#Data!et(.'ields[;].<s!tring/
for i := ( to 0red+!"#Data!et(.'ields.*o)nt. do
it.!)bItems.<00end+!"#Data!et(.'ields[i].<s!tring./
!"#Data!et(.Ne3t/
end/
finally
!"#Data!et(.*lose/
end/
end/

Aqui no estamos usando nenhuma espcie de cache, fazendo uma navegao otimizada e
unidirecional. Para cada registro do SQLDataSet, adicionamos os valores dos campos no
ListView e a seguir navegamos para o prximo registro. A figura a seguir mostra o exemplo em
execuo:

IS6LCursor
Quando usamos DataSets do dbExpress diretamente, na verdade estamos trabalhando
diretamente com o driver a ele associado. Essa "interface dbExpress com o banco de dados
feito atravs de drivers e interfaces, definidas na unit DBXpress.pas. Veja a seguir a definio
da interface responsvel pela manipulao de cursores (se voc observar, ver que usamos
alguns mtodos dessa interface no exemplo anterior):

I!"#*)rsor = interface
function !et,0tion+e,0tion: &!"#*)rsor,0tion/
Pro09al)e: #ongInt.: !"#:es)lt/ stdcall/
function =et,0tion+e,0tion: &!"#*)rsor,0tion/ Pro09al)e: Pointer/
1a3#ength: !mallInt/ out #ength: !mallInt.: !"#:es)lt/ stdcall/
function get7rror1essage+7rror: P*har.: !"#:es)lt/ overload/ stdcall/
function get7rror1essage#en+out 7rror#en: !mallInt.: !"#:es)lt/ stdcall/
function get*ol)mn*o)nt+var 0*ol)mns: >ord.: !"#:es)lt/ stdcall/
function get*ol)mnName#ength+
*ol)mnN)mber: >ord/
var 0#en: >ord.: !"#:es)lt/ stdcall/
function get*ol)mnName+*ol)mnN)mber: >ord/ 0*ol)mnName: P*har.: !"#:es)lt/
stdcall/
function get*ol)mn&y0e+*ol)mnN)mber: >ord/ var 0)&y0e: >ord/
var 0)!)b&y0e: >ord.: !"#:es)lt/ stdcall/
function get*ol)mn#ength+*ol)mnN)mber: >ord/ var 0#ength: #ong>ord.:
!"#:es)lt/ stdcall/
function get*ol)mnPrecision+*ol)mnN)mber: >ord/
var 0iPrecision: !mallInt.: !"#:es)lt/ stdcall/
function get*ol)mn!cale+*ol)mnN)mber: >ord/ var 0i!cale: !mallInt.: !"#:es)lt/
stdcall/
function isN)llable+*ol)mnN)mber: >ord/ var N)llable: #ongBool.: !"#:es)lt/
stdcall/
function is<)toIncrement+*ol)mnN)mber: >ord/ var <)toIncr: #ongBool.:
!"#:es)lt/ stdcall/
function is:ead,nly+*ol)mnN)mber: >ord/ var :ead,nly: #ongBool.: !"#:es)lt/
stdcall/
function is!earchable+*ol)mnN)mber: >ord/ var !earchable: #ongBool.:
!"#:es)lt/ stdcall/
function isBlob!i?e73act+*ol)mnN)mber: >ord/ var Is73act: #ongBool.:
!"#:es)lt/ stdcall/
function ne3t: !"#:es)lt/ stdcall/
function get!tring+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function get!hort+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function get#ong+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function getDo)ble+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function getBcd+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function get&ime!tam0+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function get&ime+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function getDate+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function getBytes+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function getBlob!i?e+*ol)mnN)mber: >ord/ var #ength: #ong>ord/
var IsBlan: #ongBool.: !"#:es)lt/ stdcall/
function getBlob+*ol)mnN)mber: >ord/ 9al)e: Pointer/
var IsBlan: #ongBool/ #ength: #ong>ord.: !"#:es)lt/ stdcall/
end/

Essa interface, juntamente com ISQLCommand, ISQLConnection e ISQLDriver compem a
arquitetura aberta do dbExpress. Se um desenvolvedor quiser criar um driver dbExpress para
acessar um banco de dados no suportado nativamente, deve implementar essas interfaces.
TCusto+S6LDataSet
A seguir, veremos as principais propriedades de TCustomSQLDataSet, que a classe base para
todos os DataSets Unidirecionais do dbExpress. No listarei os membros herdados de classes
mais altas, como TDataSet, focando nos membros introduzidos pela classe
TCustomSQLDataSet:

BlobBuffer Reserva buffer de memria para armazenar campos BLOB.
CommandText Especifica o comando que o DataSet ir executar.
CommandType Indica o tipo de comando passado no CommandText, que pode ser texto,
o nome de uma tabela ou nome de uma stored procedure.
CurrentBlobSize Tamanho do ultimo campo BLOB lido.
DataLink Identifica o Datalink que gerencia a comunicao entre o DataSet e o
DataSetMaster.
DataSource Faz um link ente o DataSet e outro DataSet Master.
DesignerData Armazena dados customizados.
GetMetadata Especifica se o DataSet obtm metadatas do BD.
IndexDefs Contm definies de todos os ndices definidos para o DataSet
InternalConnection Indica o componente que conecta o DataSet ao BD.
LastError Indica o ultimo erro SQL retornado pelo dbExpress.
MaxBlobSize Indica o nmero mximo de bytes retornados por campos BLOB.
NativeCommand Representa o comando SQL que foi enviado ao servidor SQL.
NumericMapping Configurao de mapeamento entre campos BCD.
ParamCheck Especifica se a lista de parmetros para o Dataset reconfigurada quando
a consulta muda.
ParamCount Indica o nmero de parmetros do DataSet.
Params Parmetros da consulta SQL.
Prepared Indica se o comando est preparado para execuo.
ProcParams Descrio dos parmetros de Stored Procedures.
RecordCount Indica o nmero de registros obtidos pela consulta do DataSet.
RowsAffected Indica o nmero de registros afetados pela execuo do ltimo comando
no DataSet.
SchemaInfo MetaDados do DataSet.
SortFieldNames Ordem dos dados da consulta quando o CommandType for ctTable.
SQLConnection Componente de conexo.
TransactionLevel Nvel de isolamento de transao.

Veja a seguir os principais mtodos do componente:

CreateBlobStream Cria uma Stream para campos BLOB.
GetBlobFieldData Recupera o valor corrente do campo BLOB no buffer.
GetDetailLinkFields Lista os campos da relao Master / Detail.
GetFieldData Recupera o valor corrente de um campo no buffer.
GetKeyFieldNames Preenche uma lista com os nomes de todos os ndices do DataSet.
GetQuoteChar Retorna o character usado em comandos SQL para manipular abertura e
fechamento de strings.
IsSequenced Indica se o DataSet pode usar nmeros de registros para indicar sua
ordem.
Locate Para busca de registros no DataSet, com limitaes imposta pelos
cursores unidirecionais.
Lookup Para busca de campos Lookup no DataSet, com limitaes imposta pelos
cursores unidirecionais.
ParamByName Captura um parmetro pelo nome.
PrepareStatement Prepara a execuo do comando SQL.
SetSchemaInfo Indica se o Dataset representa metadados do servidor e de que tipo.

Veja a seguir os principais eventos do componente:
ParseDeleteSql Ocorre quando a aplicao prepara para processar um comando DELETE armazenado na propriedade
CommandText.
ParseInsertSql Ocorre quando a aplicao prepara para processar um comando INSET armazenado na propriedade
CommandText.
ParseSelectSql Ocorre quando a aplicao prepara para processar um comando SELECT armazenado na propriedade
CommandText.
Parse!pdateSql Ocorre quando a aplicao prepara para processar um comando !PD"TE armazenado na propriedade
CommandText.

Parte ,I Re(uperando /etaDados

Nesta parte do curso, veremos como utilizar o dbExpress para recuperar informaes sobre
objetos do banco de dados, como nome de tabelas, campos, ndices (o que chamamos de
metadados).
dbExpress e /etaDados
No dbExpress, a interface responsvel pela obteno de metadados a ISQLMetaData,
declarada na unit DBXpress.pas da seguinte forma:

I!"#1etaData = interface
function !et,0tion+eD,0tion: &!"#1etaData,0tion/
Pro09al)e: #ongInt.: !"#:es)lt/ stdcall/
function =et,0tion+eD,0tion: &!"#1etaData,0tion/ Pro09al)e: Pointer/
1a3#ength: !mallInt/ o)t #ength: !mallInt.: !"#:es)lt/ stdcall/
function get,b-ect#ist+e,b-&y0e: &!"#,b-ect&y0e/ out *)rsor: I!"#*)rsor.:
!"#:es)lt/ stdcall/
function get&ables+&ableName: P*har/ &able&y0e: #ong>ord/
out *)rsor: I!"#*)rsor.: !"#:es)lt/ stdcall/
function getProced)res+Proced)reName: P*har/ Proc&y0e: #ong>ord/
out *)rsor: I!"#*)rsor.: !"#:es)lt/ stdcall/
function get*ol)mns+&ableName: P*har/ *ol)mnName: P*har/
*ol&y0e: #ong>ord/ ,)t *)rsor: I!"#*)rsor.: !"#:es)lt/ stdcall/
function getProced)reParams+ProcName: P*har/ ParamName: P*har/
out *)rsor: I!"#*)rsor.: !"#:es)lt/ stdcall/
function getIndices+&ableName: P*har/ Inde3&y0e: #ong>ord/
out *)rsor: I!"#*)rsor.: !"#:es)lt/ stdcall/
function get7rror1essage+7rror: P*har.: !"#:es)lt/ overload/ stdcall/
function get7rror1essage#en+o)t 7rror#en: !mallInt.: !"#:es)lt/ stdcall/
end/

Como voc pode notar pelos mtodos, podemos recuperar praticamente qualquer informao
do catlogo do BD, como nomes de tabelas, tipos e nomes de campos, informaes sobre
Stored Procedures e mais. Para usar essa interface, devemos usar o mtodo SetSchemaInfo de
um DataSet do dbExpress.
Ap#%(a!o usando /etaDados
Inicie uma nova aplicao VCL no Delphi.

Figura 1.
Coloque SQLConnection no e configure uma conexo para o banco Employee do Interbase ou
do Firebird (j discutimos conexes anteriormente, de forma que no vou entrar em detalhes
aqui).

Figura 2.
Coloque mais alguns componentes dbExpress e da paleta Data Access, conforme mostrado a
seguir:

Figura 3.
Configure o relacionamento entre os componentes da seguinte forma:

obect DB!rid"# $DB!rid
DataSo%rce & DataSo%rce"
end
obect DB!rid'# $DB!rid
DataSo%rce & DataSo%rce'
end
obect SQLQ%ery"# $SQLQ%ery
SQLConnection & SQLConnection"
end
obect DataSet(ro)ider"# $DataSet(ro)ider
DataSet & SQLQ%ery"
end
obect ClientDataSet"# $ClientDataSet
(ro)ider*ame & +DataSet(ro)ider"+
end
obect DataSo%rce"# $DataSo%rce
DataSet & ClientDataSet"
end
obect SQLQ%ery'# $SQLQ%ery
SQLConnection & SQLConnection"
end
obect DataSet(ro)ider'# $DataSet(ro)ider
DataSet & SQLQ%ery'
end
obect ClientDataSet'# $ClientDataSet
(ro)ider*ame & +DataSet(ro)ider'+
end
obect DataSo%rce'# $DataSo%rce
DataSet & ClientDataSet'
end
No evento ,nCreate do formulrio digite o seguinte:

procedure &'orm(.'orm*reate+!ender: &,b-ect./
begin
!"#")ery(.!et!chemaIn5o+st&ables@22@22./
*lientData!et(.,0en/
end/

E no e#ento OnDateChange do DataSource1 di$ite o se$uinte%

procedure &'orm(.Data!o)rce(Data*hange+!ender: &,b-ect/ 'ield: &'ield./
var
tb: string/
begin
*lientData!etA.*lose/
tb := *lientData!et(.'ieldByName+2&<B#7_N<172..<s!tring/
!"#")eryA.!et!chemaIn5o+st*ol)mns@tb@22./
*lientData!etA.,0en/
end/

Com isso, exibimos no primeiro DB!rid as tabelas do banco de dados. Quando uma tabela for
selecionada, exibimos informaes sobre suas colunas no segundo DB!rid.
Execute a aplicao:

Figura 4.
Parte ,II 9nd%(es e+ +e+:r%a

A partir desta parte do curso, vamos conhecer algumas tcnicas avanadas de
desenvolvimento com dbExpress e DataSnap, principalmente atravs do componente
ClientDataSet.
O exemplo apresentado neste artigo mostra como definir ndices em memria para o
ClientDataSet. Para isso, basta setar a propriedade Inde-Field*ames (para criar ndices mais
personalizados use a propriedade Inde-Defs e Inde-*ame). No necessrio criar arquivos de
ndices como no Paradox ou refazer a consulta SQL no banco.
Inicie uma nova aplicao Delphi VCL e coloque no formulrio principal coloque um ComboBo-,
Label, ClientDataSet, DataSo%rce e DB!rid, fazendo as ligaes como mostrado abaixo:

object *lientData!et(: &*lientData!et
end

object Data!o)rce(: &Data!o)rce
Data!et = *lientData!et(
end

object DB=rid(: &DB=rid
Data!o)rce = Data!o)rce(
end

D um clique de direita no ClientDataSet, escolha Load from MyBase $able e abra o arquivo
C%stomer.XML. localizado nos demos do Delphi, por padro no diretrio:

*:\<rB)ivos de 0rogramas\<rB)ivos com)ns\Borland !hared\Data

Seu formulrio deve estar semelhante ao mostrado a seguir:

Figura 1.
No evento ,nCreate do formulrio digite:

procedure &'rm1ain.'orm*reate+!ender: &,b-ect./
begin
*lientData!et(.=et'ieldNames+*omboBo3(.Items./
end/

Isso preenche o Combo com a lista de campos disponveis no ClientDataSet.

Figura 2.
No evento ,nChan/e do Combo, ordenamos o ClientDataSet atravs do campo que o usurio
selecionou:

procedure &'rm1ain.*omboBo3(*hange+!ender: &,b-ect./
begin
*lientData!et(.Inde3'ieldNames := *omboBo3(.&e3t/
end/

Fazemos isso tambm no ,n$ileClic0 do DB!rid, para ordenar o DataSet conforme a coluna
clicada no grid:

procedure &'rm1ain.DB=rid(&itle*lic+*ol)mn: &*ol)mn./
begin
if <ssigned+,ld*ol)mn. then
,ld*ol)mn.&itle.*olor := DB=rid(.'i3ed*olor/
*lientData!et(.Inde3'ieldNames := *ol)mn.'ieldName/
*ol)mn.&itle.*olor := C;;D;E;E;/
,ld*ol)mn := *ol)mn/
end/

A figura a seguir mostra a aplicao em execuo, observe o efeito de cor que colocamos na
coluna:

Figura 3.
Parte ,III DataSet5%e#ds

Este exemplo mostra como utilizar DataSetFields em ClientDataSets. DataSetField um campo
$Field especial que pode representar o contedo de outro DataSet.
Configure uma conexo dbExpress para o banco EMPLOYEE do Interbase. Coloque um
SQLConnection apontando para essa conexo. Coloque tambm duas SQLQ%ery, um
DataSet(ro)ider, um ClientDataSet, dois DataSo%rces, um DB!rid, um B%tton e um
DB*a)i/ator.
Relacione os componentes conforme mostrado a seguir:

object !"#*onnection(: &!"#*onnection
end

object !"#")ery(: &!"#")ery
!"#*onnection = !"#*onnection(
7nd

object !"#")eryA: &!"#")ery
!"#*onnection = !"#*onnection(
7nd

object Data!o)rce(: &Data!o)rce
Data!et = !"#")ery(
7nd

object Data!etProvider(: &Data!etProvider
Data!et = !"#")ery(
7nd

object DB=rid(: &DB=rid
Data!o)rce = Data!o)rceA
7nd

object DBNavigator(: &DBNavigator
Data!o)rce = Data!o)rceA
7nd

object *lientData!et(: &*lientData!et
ProviderName = 2Data!etProvider(2
7nd

object Data!o)rceA: &Data!o)rce
Data!et = *lientData!et(
end

Seu formulrio deve estar semelhante ao mostrado a seguir:

Figura 1.
Configura a instruo SQL da primeira Q%ery para:

select 8 5rom *U!&,17:

E da segunda para:

select 8 5rom !<#7!
where *U!&_N,=:*U!&_N,

Configure o parmetro (propriedade (arams) da segunda Q%ery como mostrado a seguir:

Figura 2.
Adicione todos os $Field no ClientDataSet, e observe que teremos um DataSetField:

Figura 3.
Esse campo representa o DataSet detalhe. Com isso temos no mesmo DataSet acesso a tabela
principal (master) e tabela detalhe (detail).
No evento ,nCreate do form digite:

procedure &'rm1ain.'orm*reate+!ender: &,b-ect./
begin
*lientData!et(.,0en/
end/

No evento ,nClic0 do boto digite:

procedure &'rm1ain.BitBtn(*lic+!ender: &,b-ect./
begin
*lientData!et(.<00lyU0dates+;./
end/

A figura a seguir mostra a aplicao em execuo.

Figura 4.
Navegue at a ltima coluna do DB!rid e observe que ela lista o DataSetField. Clique em [...]
e note que uma outra DB!rid ser aberta automaticamente, mostrando dados da tabela
detalhe, relacionados com o registro selecionado no DB!rid principal.

Figura 5.
Note que usamos para isso somente u+ ;n%(o C#%entDataSet. Alm disso, alteraes no
DataSetField sero refletidos no DataSet principal (por isso s precisamos de um
Apply1pdates, que aplicar alteraes em ambas as tabelas no banco).
Parte I< Interna#Ca#(

Este exemplo mostra como utilizar o recurso de InternalCalc em ClientDataSets, utilizado para
otimizar campos calculados em memria. Faremos um exemplo que vai compara campos
calculados tradicionais com InternalCalcs.
O evento ,nCalcFields de um DataSet uma "armadilha. Ele , obviamente, utilizado para
implementar campos calculados. O que poucos sabem que esse evento chamado a todo o
momento, por exemplo, quando um valor de um campo muda, mesmo que esse campo no
afete o valor do clculo. Se voc escrever um cdigo mais complexo nesse evento, como uma
consulta ao banco de dados para obter um valor a ser usado no clculo (o que considero um
"suicdio), ver que a performance da sua aplicao cair consideravelmente.
A soluo criar o campo como InternalCalc ao invs de Calc%lated. A seguir, no evento
,nCalcFields, testamos se o estado (State) do DataSet dsInternalCalc antes de fazermos o
processamento, como no exemplo:

if *lientData!et(.!tate = dsInternal*alc then
*lientData!et(*<1P,.9al)e := ...

Com isso, o cdigo ser executado uma nica vez para cada registro, por exemplo quando h
uma navegao ou quando um (ost chamado.
Para ver um exemplo prtico, coloque um ClientDataSet no formulrio e um DataSo%rce. D
um duplo clique no componente e clique de direita no editor, escolhendo *e2 Field (vamos
criar um DataSet de memria neste exemplo).
Adicione o campo NUM1 como mostrado a seguir:

Figura 1.
Adicione o campo NUM2 como mostrado a seguir:

Figura 2.
Adicione o campo DUMMY como mostrado a seguir:

Figura 3.
Adicione o campo CALCULATED como mostrado a seguir (observe que ele ser um campo
calculado):

Figura 4.
Adicione o campo INTERNALCALC como mostrado a seguir (observe que ele ser um campo
InternalCalc):

Figura 5.
Arraste os campos criados para o formulrio, para que sejam criados os controles Data-Aware.
Coloque tambm um DB*a)i/ator apontando para o DataSo%rce.
Seu formulrio deve estar semelhante ao mostrado a seguir:

Figura 6.
Neste exemplo, vamos processar o clculo de NUM1 e NUM2 e atribuir a ambos os campos
calculados, sem cada um de um tipo (um internal e outro no). Para isso, no evento
,nCalcFields do ClientDataSet, digitamos:

procedure &'rm1ain.*lientData!et(*alc'ields+Data!et: &Data!et./
begin
inherited/
F calc)lado normalG
*lientData!et(*<#*U#<&7D.<sInteger :=
*lientData!et(NU1(.<sInteger H
*lientData!et(NU1A.<sInteger/
Finternal calcG
if *lientData!et(.!tate = dsInternal*alc then
*lientData!et(IN&7:N<#*<#*.<sInteger :=
*lientData!et(NU1(.<sInteger H
*lientData!et(NU1A.<sInteger/
end/

Execute a aplicao e digite dois valores, para NUM1 e NUM2:

Figura 7.
Para ver o campo em ao, coloque dois Bre0points no cdigo conforme mostrado a seguir:

Figura 8.
Agora digite um valor qualquer no campo DUMMY, observe que ele no afeta o clculo, pois
no serve para nada (no participa da soma). Mesmo assim, note que o cdigo do campo
calculado ser executado, mesmo que a soma no seja afetada por DUMMY.
O processo no o mesmo para o campo InternalCalc (no segundo brea0point), ele ser
executado somente uma vez para fazer a soma, quando voc der o (ost no DataSet (mais
otimizado).

Figura 9.
Parte < UpdateStatus

Este exemplo mostra como utilizar as propriedades 1pdateStat%s e 1pdateFilter do
ClientDataSet. Enquanto o State indica o estado de um DataSet %nte%ro, 1pdateStat%s
representa o estado atua# de u+ re-%stro. Stat%sFilter permite exibir filtrar os registros de
acordo com seu estado.
Inicie uma nova aplicao Delphi VCL e coloque no formulrio principal um ComboBo- e um
ClientDataSet. D um clique de direita no ClientDataSet, escolha Load from MyBase $able e
abra o arquivo C%stomer.XML. localizado nos demos do Delphi, por padro no diretrio:

*:\<rB)ivos de 0rogramas\<rB)ivos com)ns\Borland !hared\Data

Adicione os $Fields no DataSet e adicione um campo calculado, chamado STATUS, conforme
mostrado a seguir:

Figura 1.
Arraste os campos para o formulrio para criar os controles Data-Aware. Coloque tambm um
DB*a)i/ator apontando para o DataSo%rce.
Seu formulrio deve estar semelhante ao mostrado a seguir:

Figura 2.
No ,nCreate do form, digite:

uses &y0In5o/
...
procedure &'rm1ain.'orm*reate+!ender: &,b-ect./
var
i : integer/
begin
for i := ; to $ do
*omboBo3(.Items.<dd+=et7n)mName+&y0eIn5o+&U0date!tat)s.@I../
*omboBo3(.Items.<dd+2&odos2./
end/

Isso preenche o Combo com os possveis valores para a enumerao $1pdateStat%s:

&U0date!tat)s = +)sUnmodi5ied@ )s1odi5ied@ )sInserted@ )sDeleted./
&U0date!tat)s!et = set of &U0date!tat)s/

Figura 3.
No evento ,nCalcFields digite:

procedure &'rm1ain.*lientData!et(*alc'ields+Data!et: &Data!et./
begin
*lientData!et(!&<&U!.<s!tring :=
=et7n)mName+&y0eIn5o+&U0date!tat)s.@Integer+*lientData!et(.U0date!tat)s../
end/

Isso faz com que o campo STATUS indique o status atual do registro.
Quando o usurio selecione um Status na combo, vamos exibir somente os registros que
estejam naquele estado (excludo, inserido, modificado etc.). Isso feito no evento ,nChan/e
do Combo:

procedure &'rm1ain.*omboBo3(*hange+!ender: &,b-ect./
begin
if *omboBo3(.ItemInde3 = D then
*lientData!et(.!tat)s'ilter := []
else
*lientData!et(.!tat)s'ilter := [&U0date!tat)s+*omboBo3(.ItemInde3.]/
end/

Execute a aplicao, insira, modifique e exclua alguns registros, e a seguir escolha o filtro.

Figura 4.
Parte <I Data )s8 De#ta

Este exemplo apresenta o uso das propriedades Data e Delta do ClientDataSet. Data um
,LE3ariant que armazena a cache de dados, Delta um OLEVariant que armazena as
ALTERAES feitas em um ClientDataSet.
Inicie uma nova aplicao Delphi VCL e coloque no formulrio principal coloque um B%tton,
dois ClientDataSets, dois DataSo%rce'. dois DB!ridse um DB*a)i/ator, fazendo as ligaes
como mostrado abaixo:

object *lientData!et(: &*lientData!et
end

object Data!o)rce(: &Data!o)rce
Data!et = *lientData!et(
end

object DB=rid(: &DB=rid
Data!o)rce = Data!o)rce(
end

object *lientData!etA: &*lientData!et
end

object Data!o)rceA: &Data!o)rce
Data!et = *lientData!etA
end

object DB=ridA: &DB=rid
Data!o)rce = Data!o)rceA
end

object DBNavigator(: &DBNavigator
Data!o)rce = Data!o)rce(
end

D um clique de direita no ClientDataSet, escolha Load from MyBase $able e abra o arquivo
C%stomer.XML. localizado nos demos do Delphi, por padro no diretrio:

*:\<rB)ivos de 0rogramas\<rB)ivos com)ns\Borland !hared\Data

Seu formulrio deve estar semelhante ao mostrado a seguir:

Figura 1.
No evento ,nClic0 do boto capturamos o Delta do primeiro CDS e jogamos como Data do
segundo CDS:

procedure &'rm1ain.BitBtn(*lic+!ender: &,b-ect./
begin
if *lientData!et(.*hange*o)nt I ; then
*lientData!etA.Data := *lientData!et(.Delta/
end/

Execute a aplicao. Faa algumas modificaes no primeiro DB!rid e observe que, ao clicar
no boto, essas alteraes so registradas no segundo DB!rid:

Figura 2.
No exemplo anterior, modifiquei o campo Company de um registro. O CDS mantm os valores
originais em Delta para serem utilizados no processo de 4esol)in/ do DataSet(ro)ider, quando
os campos precisam ser processados em instrues SQL de atualizao.
Parte <II C#%entDataSet e </L

Neste artigo veremos alguns interessantes recursos do ClientDataSet para suporte a XML.
Atravs de uma aplicao dbExpress tpica, vamos salvar os dados obtidos em XML para o
disco, ler, examinar a estrutura do DataPacket e o XML em memria.
O suporte a XML no se restringe simplesmente ao salvamento dos dados para o disco em um
formato estruturado. A Borland inclui essa funcionalidade no componente para que possamos
facilmente trafegar DataSets pela Web em formato XML, usando o SOAP (Simple ,bect Access
(rotocol).
Configure uma conexo dbExpress para o banco EMPLOYEE do Interbase. Coloque um
SQLConnection apontando para essa conexo. Coloque tambm duas SQLQ%ery, um
DataSet(ro)ider, um ClientDataSet, dois DataSo%rces, um DB!rid, quatro B%ttons, um
DB*a)i/ator, um Memo e um $5ebBro2ser (paleta Internet).
Relacione os componentes conforme mostrado a seguir:

object !"#*onnection(: &!"#*onnection
end

object !"#")ery(: &!"#")ery
!"#*onnection = !"#*onnection(
7nd

object !"#")ery(: &!"#")ery
!"#*onnection = !"#*onnection(
End

object Data!etProvider(: &Data!etProvider
Data!et = !"#")ery(
End

object DB=rid(: &DB=rid
Data!o)rce = Data!o)rceA
End

object DBNavigator(: &DBNavigator
Data!o)rce = Data!o)rceA
End

object *lientData!et(: &*lientData!et
ProviderName = 2Data!etProvider(2
End

A instruo SQL da SQLQ%ery" mostrada a seguir:

select 8 5rom 71P#,J77

Seu formulrio deve estar semelhante ao mostrado a seguir:

Figura 1.

O cdigo do boto ,pen mostrado a seguir:

procedure &'orm(.btn,0en*lic+!ender: &,b-ect./
begin
*lientData!et(.,0en/
end/

O cdigo do boto Sa)e XML mostrado a seguir:

procedure &'orm(.B)ttonA*lic+!ender: &,b-ect./
begin
*lientData!et(.!ave&o'ile+2c:\7m0loyee.3ml2./
>ebBrowser(.Navigate+2file:KKKc:\7m0loyee.3ml2./
end/

O cdigo do boto Load XML mostrado a seguir:

procedure &'orm(.B)tton$*lic+!ender: &,b-ect./
begin
*lientData!et(.#oad'rom'ile+2c:\7m0loyee.3ml2./
end/

O cdigo do boto XML Data mostrado a seguir:

procedure &'orm(.B)ttonD*lic+!ender: &,b-ect./
begin
1emo(.#ines.&e3t := *lientData!et(.L1#Data/
end/

Execute a aplicao e clique nos botes ,pen. Sa)e XML e XML Data. Observe o resultado na
figura a seguir:

Figura 2.
A propriedade XMLData, somente-leitura, permite o acesso as dados em XML do ClientDataSet
sem a necessidade de salvamento no disco, ideal para por exemplo trafegarmos informaes
via Web Services / SOAP.
O mtodo Sa)e$oFile salva o Data(ac0et para o disco. Usamos um WebBrowser para exibir o
XML dentro do form, atravs de um plugin do Internet Explorer usado pelo componente.
Observe que voc pode expandir e reduzir nodes. Tambm possvel fazer isso no browser,
claro:

Figura 3.
Inclua, exclua, altere alguns registros no DB!rid e salve novamente o XML. Abra o arquivo
para examinarmos seu formato.

xml version="1.0" standalone="yes" ?>
- <DATAPACKET Version="2.0">
- <METADATA>
- <FIELDS>
<FIELD attrname="EMP_N" fieldtype="i2" required="true" />
<FIELD attrname="!"#$%_N&ME" fieldtype="string" required="true" WIDTH="'(" />
<FIELD attrname=")&$%_N&ME" fieldtype="string" required="true" WIDTH="20" />
<FIELD attrname="P*NE_E+%" fieldtype="string" WIDTH="," />
<FIELD attrname="*"#E_-&%E" fieldtype="$.)date%i/e" required="true" />
<FIELD attrname="-EP%_N" fieldtype="string" required="true" SUBTYPE="!ixed0har"
WIDTH="1" />
<FIELD attrname="23_0-E" fieldtype="string" required="true" WIDTH="(" />
<FIELD attrname="23_4#&-E" fieldtype="i2" required="true" />
<FIELD attrname="23_05N%#6" fieldtype="string" required="true" WIDTH="'(" />
<FIELD attrname="$&)&#6" fieldtype="fixed!M%" required="true" DECIMALS="2"
WIDTH="'(" />
<FIELD attrname="!5))_N&ME" fieldtype="string" WIDTH="17" />
FIELDS>
<PARAMS LCID="0" />
METADATA>
- <ROWDATA>
<ROW EMP_NO="2" FIRST_NAME="4uinther" LAST_NAME="Nelson" PHONE_EXT="2(0"
HIRE_DATE="'899'229" DEPT_NO=":00" JOB_CODE=";P" JOB_GRADE="2"
JOB_COUNTRY="5$&" SALARY="'0(800.00" FULL_NAME="Nelson< 4uinther" />
<ROW EMP_NO="," FIRST_NAME="3ruce" LAST_NAME="6oung" PHONE_EXT="211"
HIRE_DATE="'899'229" DEPT_NO=":2'" JOB_CODE="Eng" JOB_GRADE="2"
JOB_COUNTRY="5$&" SALARY="87(00.00" FULL_NAME="6oung< 3ruce" />
<ROW EMP_NO="(" FIRST_NAME=">i/" LAST_NAME=")a/bert" PHONE_EXT="22"
HIRE_DATE="'898020:" DEPT_NO="'10" JOB_CODE="Eng" JOB_GRADE="2"
JOB_COUNTRY="5$&" SALARY="'027(0.00" FULL_NAME=")a/bert< >i/" />
... de/ais registros o/itidos
ROWDATA>
DATAPACKET>

Um Data(ac0et contm duas sees principais: MetaData e 4o2Data. Na seo MetaData
temos informaes que definem os campos do DataSet (Fields) e tambm os parmetros
extras que inclumos no Data(ac0et ((arams). Em 4o2Data temos informaes sobre os
registros, inclusive que foram modificados.
Finalmente, execute a aplicao e carregue o DataSet sem efetuar a consulta ao BD, clicando
em Load XML:

Figura 4.
Lembre-se que muitas operaes podem ser realizadas em tempo de design, clicando-se de
direita sobre o ClientDataSet:

Figura 5.
Uma ltima dica que voc pode "roubar dados de qualquer tipo de DataSet em designtime e
jogar na memria do ClientDataSet. Por exemplo, coloque uma Table do BDE apontando para
DBDemos>Employee.DB. Coloque um ClientDataSet. d um clique de direita sobre ele escolha
a opo Assi/n Local Data:

Figura 6.

Figura 7.
Observe que os dados foram colocados no Data do CDS (veja o arquivo DFM abaixo):

Figura 8.
Agora voc pode acessar os menus de contexto e salvar para XML fcil e rapidamente. Ideal
para extrair dados de qualquer banco e salvar rapidamente em XML.
Parte <III Ap#%(a7es des(one(tadas
Neste exemplo, veremos como usar o dbExpress e ClientDataSet para obter dados do banco de
dados, sem no entanto manter uma conexo sempre ativa com o mesmo. Isso far com que
suas aplicaes se tornem mais escalveis e apresentem uma melhor performance quando o
nmero de clientes aumentar.
Para isso, vamos fazer o seguinte: abriremos a conexo e o cursor de dados somente o tempo
mnimo necessrio para executar o select. A partir da, o DataSet(ro)ider ir empacotar os
dados em um Data(ac0et que ser armazenado no Data do ClientDataSet. A seguir, fechamos
a consulta e a conexo, e o usurio poder continuar trabalhando normalmente (com dados
em cache). Quando for necessrio aplicar os dados no servidor, abrimos novamente a conexo
e enviamos o Delta.
O mais interessante de tudo que o prprio DataSet(ro)ider j realiza a maioria desse
trabalho para ns: ele sabe exatamente o momento que se faz necessria uma conexo, se
encarrega de abri-la, executar a query (que tambm aberta por ele) e assim por diante.
Precisamos apenar configurar algumas propriedades. Vamos a prtica.
Configure uma conexo dbExpress para o banco EMPLOYEE do Interbase. Coloque um
SQLConnection apontando para essa conexo. Coloque tambm um SQLQ%ery, um
DataSet(ro)ider, um ClientDataSet, um DataSo%rce, um DB!rid, dois B%ttons e um Memo.
Configure os componentes conforme o cdigo a seguir:

object DB=rid(: &DB=rid
Data!o)rce = Data!o)rce(
end
object Data!o)rce(: &Data!o)rce
Data!et = *lientData!et(
end
object *lientData!et(: &*lientData!et
ProviderName = 2Data!etProvider(2
end
object Data!etProvider(: &Data!etProvider
Data!et = !"#")ery(
end
object !"#")ery(: &!"#")ery
!"#*onnection = !"#*onnection(
end
object !"#*onnection(: &!"#*onnection
*onnectionName = 271P#,J772
#oginProm0t = 'alse
*onnected = 'alse
Mee0*onnection = 'alse
Params.!trings = +
2DriverName=Interbase2
2Database=*:\Borland\InterBase\e3am0les\database\em0loyee.gdb2
2User_Name=sysdba2
2Password=masterey2
2!erver*har!et=>IN(ANA2
2!"#Dialect=$2.
end

Seu formulrio deve estar semelhante ao mostrado a seguir:

Figura 1.

Figura 2.
Observe como configurei as propriedades Connected e 6eepConnection do SQLConnection,
ambas para False. A SQLQ%ery tambm tem o Acti)e configurado para False.
O cdigo do boto E-ec%tar repassa para a SQLQ%ery a instruo SQL (Select) digitada no
Memo:

procedure &'rm1ain.BitBtn(*lic+!ender: &,b-ect./
begin
!"#")ery(.!"#.<ssign+1emo(.#ines./
*lientData!et(.*lose/
*lientData!et(.,0en/
end/

Execute a aplicao, digite uma instruo SQL e clique no boto E-ec%tar (veja a figura a
seguir).

Figura 3.
Quando fazemos a consulta, os seguintes procedimentos foram realizados pelo dbExpress:
ClientDataSet (CDS) recebe a chamada ao ,pen;
CDS chama o mtodo de interface As7!et4ecords;
DataSetProvider (DSP) recebe a chamada ao GetRecords;
DSP abre a conexo (SQLConnection);
DSP abre o cursor da SQLQuery;
DSP varre os dados da consulta;
DSP empacota os dados;
DSP fecha o cursor (SQLQuery);
DSP verifica a propriedade KeepConnection, como est False, fecha a conexo com
o BD;
DSP envia o DATA ao CDS;
CDS fica com dados em memria.

Mesmo com a aplicao em execuo, podemos comprovar que no h nenhuma conexo ativa
com o servidor.

Figura 4.
O boto Apply simplesmente chama o Apply1pdates para atualizar o BD: o DSP se encarregar
de abrir todas conexes necessrias e novamente, fechar aps a operao.
Use o 6eepConnection com cuidado: em um cenrio onde o cliente ir frequentemente enviar
solicitaes (selects, updates etc.) ao BD, no uma boa soluo ter essa propriedade
configurada. Ela ideal para quando o usurio ir trabalhar de forma desconectada, em um
conjunto de dados maior, por um longo perodo de tempo.
Outro lembrete: no use o (ac0et 4ecords com essa abordagem, pois exige intensa
comunicao com o servidor SQL. Pelo motivo anterior, essa combinao no faria sentido.
Parte <I, Ca(*e BDE x Ca(*4 C#%entDataSet
Neste exemplo vamos estudar um pouco sobre o mecanismo de cache do ClientDataSet.
Aproveitarei para fazer alguns comparativos com o mecanismo de cache do BDE, para aqueles
que esto migrando de soluo. Ou seja, a aplicao que preparei um comparativo entre o
mecanismo de cache do BDE (Cache Updates) e a cache (Data) do ClientDataSet.
Configure uma conexo dbExpress para o banco EMPLOYEE do Interbase. Coloque um
SQLConnection apontando para essa conexo. Coloque tambm um SQLQ%ery, um
DataSet(ro)ider, um ClientDataSet, um DataSo%rce, dois DB!rids e dois B%ttons. Da mesma
forma, configure um acesso BDE para o mesmo banco de dados. Os componentes so:
DataBase. Q%ery. 1pdateSQL e DataSo%rce. Configure-os como mostrado na listagem a
seguir:

object DB=rid(: &DB=rid
Data!o)rce = Data!o)rce(
end
object DB=ridA: &DB=rid
Data!o)rce = Data!o)rceA
end
object !"#*onnection(: &!"#*onnection
*onnectionName = 271P#,J772
DriverName = 2Interbase2
=etDriver')nc = 2get!"#DriverIN&7:B<!72
#ibraryName = 2dbe30int.dll2
#oginProm0t = 'alse
Params.!trings = +
2DriverName=Interbase2
2Database=*:\Borland\InterBase\e3am0les\database\em0loyee.gdb2
2:oleName=:oleName2
2User_Name=sysdba2
2Password=masterey2
2!erver*har!et=2
2!"#Dialect=$2
2Blob!i?e=O(2
2*ommit:etain='alse2
2>ait,n#ocs=&r)e2
27rror:eso)rce'ile=2
2#ocale*ode=;;;;2
2Interbase &ransIsolation=:ead*ommited2
2&rim *har='alse2.
9endor#ib = 2gds$A.dll2
end
object !"#")ery(: &!"#")ery
!"#.!trings = +
2select 8 5rom *U!&,17:2.
!"#*onnection = !"#*onnection(
end
object Data!o)rce(: &Data!o)rce
Data!et = *lientData!et(
end
object Database(: &Database
DatabaseName = 2#,*<#2
DriverName = 2IN&:B<!72
#oginProm0t = 'alse
Params.!trings = +
2!7:97: N<17=IB_!7:97::KP<&PKD<&<B<!7.=DB2
2U!7: N<17=!J!DB<2
2,P7N 1,D7=:7<DK>:I&72
2!*P71< *<*P7 !IQ7=E2
2#<N=D:I97:=2
2!"#":J1,D7=2
2!"#P<!!&P:U 1,D7=!P<:7D <U&,*,11I&2
2!*P71< *<*P7 &I17=O(2
21<L :,>!=O(2
2B<&*P *,UN&=A;;2
27N<B#7 !*P71< *<*P7='<#!72
2!*P71< *<*P7 DI:=2
27N<B#7 B*D='<#!72
2B#,B! &, *<*P7=RD2
2B#,B !IQ7=$A2
2><I& ,N #,*M!='<#!72
2*,11I& :7&<IN='<#!72
2:,#7 N<17=2
2P<!!>,:D=masterey2.
!essionName = 2De5a)lt2
end
object ")ery(: &")ery
*achedU0dates = &r)e
DatabaseName = 2#,*<#2
!"#.!trings = +
2select 8 5rom *U!&,17:2.
U0date,b-ect = U0date!"#(
end
object U0date!"#(: &U0date!"#
end
object Data!etProvider(: &Data!etProvider
Data!et = !"#")ery(
end
object *lientData!et(: &*lientData!et
ProviderName = 2Data!etProvider(2
end
object Data!o)rceA: &Data!o)rce
Data!et = ")ery(
end

Seu formulrio deve estar semelhante ao mostrado a seguir:

Figura 1.
Para ver como a cache funciona em ambos os engines, criei um mtodo que adiciona 5 mil
registros em um DataSet passado como parmetro. Ele gera valores strings randomizados para
cada ccampo da tabela:

procedure &'rm1ain.<00end:andom:ecords+Data!et: &Data!et./
var
i : integer/
begin
Data!et.,0en/
for i := ( to N;;; do
begin
Data!et.<00end/
Data!et.'ieldByName+2*U!&_N,2..<sInteger := I/
Data!et.'ieldByName+2*U!&,17:2..<s!tring := :andom!tr/
Data!et.'ieldByName+2*,N&<*&_'I:!&2..<s!tring := :andom!tr/
Data!et.'ieldByName+2*,N&<*&_#<!&2..<s!tring := :andom!tr/
Data!et.'ieldByName+2<DD:7!!_#IN7(2..<s!tring := :andom!tr/
Data!et.'ieldByName+2<DD:7!!_#IN7A2..<s!tring := :andom!tr/
Data!et.'ieldByName+2!&<&7_P:,9IN*72..<s!tring := :andom!tr/
Data!et.P,!&/
<00lication.Process1essages/
end/
end/

No boto Iniciar de cada engine, chamamos o mtodo passando o respectivo DataSet (Query
do BDE ou ClientDataSet do DataSnap):

procedure &'rm1ain.BitBtn(*lic+!ender: &,b-ect./
begin
<00end:andom:ecords+*lientData!et(./
end/

procedure &'rm1ain.BitBtnA*lic+!ender: &,b-ect./
begin
<00end:andom:ecords+")ery(./
end/

Aps iniciar a insero de registros aleatrios, observe que a aplicao consome mais memria
(Task Manager) quando se usa o CDS. Isso comprova que todas as alteraes e updates ficam
no processo da aplicao, em memria.

Figura 2.

Figura 3.
No BDE, so criados arquivos no disco (veja dir. atual da aplicao) para armazenar as
atualizaes, como comprova a figura a seguir.

Figura 4.

Figura 5.
Com isso, vemos que o DataSnap usa um mecanismo de cache muito mais inteligente e
efetivo. Aplicaes com DataSnap sero bem mais escalveis e rpidas. O BDE no foi feito e
no est preparado para a criao de solues desse tipo, deficincia que foi suprida pelo
dbExpress e ClientDataSet.
Parte <, Pa(=et Re(ords
Neste exemplo veremos como usar o recurso de (ac0et 4ecords do ClientDataSet.
Configurando essa propriedade, podemos instruir ao servidor de aplicao que "empacote e
envie dados por demanda. Quando temos um grande select no servidor, podemos instruir ao
DataSet(ro)ider que v enviando essas informaes aos poucos, para otimizar o trfego de
dados. importante notar desde j, que essa abordagem menos escalvel: necessrio
manter o cursor e conexo ativos durante todo o processo.
Configure uma conexo dbExpress para o banco EMPLOYEE do Interbase. Coloque um
SQLConnection apontando para essa conexo. Coloque tambm um SQLQ%ery, um
DataSet(ro)ider, um ClientDataSet, um DataSo%rce, um DB!rid, um DB*a)i/ator, um Memo e
um SQLMonitor. Para configurar o recurso em tempo de execuo, coloque tambm um
4adio!ro%p, dois Chec0Bo-es. um SpinEdit. A Figura a seguir mostra como ficou o form:

Figura 1.

A listagem a seguir mostra como cada componente foi configurado:

object DB=rid(: &DB=rid
Data!o)rce = Data!o)rce(
end
object DBNavigator(: &DBNavigator
Data!o)rce = Data!o)rce(
end
object !"#*onnection(: &!"#*onnection
*onnectionName = 271P#,J772
DriverName = 2Interbase2
=etDriver')nc = 2get!"#DriverIN&7:B<!72
#ibraryName = 2dbe30int.dll2
#oadParams,n*onnect = &r)e
#oginProm0t = 'alse
Params.!trings = +
2DriverName=Interbase2
2Database=*:\Borland\InterBase\e3am0les\database\em0loyee.gdb2
2:oleName=:oleName2
2User_Name=sysdba2
2Password=masterey2
2!erver*har!et=2
2!"#Dialect=$2
2Blob!i?e=O(2
2*ommit:etain='alse2
2>ait,n#ocs=&r)e2
27rror:eso)rce'ile=2
2#ocale*ode=;;;;2
2Interbase &ransIsolation=:ead*ommited2
2&rim *har='alse2.
9endor#ib = 2gds$A.dll2
#e5t = SA
&o0 = A$A
end
object !"#")ery(: &!"#")ery
!"#.!trings = +
2select 8 5rom *U!&,17:2.
!"#*onnection = !"#*onnection(
end
object Data!etProvider(: &Data!etProvider
Data!et = !"#")ery(
end
object *lientData!et(: &*lientData!et
ProviderName = 2Data!etProvider(2
end
object Data!o)rce(: &Data!o)rce
Data!et = *lientData!et(
end
object !"#1onitor(: &!"#1onitor
!"#*onnection = !"#*onnection(
end

No boto 4efresh verificamos as configuraes de tela e configuramos o (ac0et 4ecords do
ClientDataSet:

procedure &'rm1ain.BitBtnA*lic+!ender: &,b-ect./
begin
1emo(.#ines.*lear/
if *hecBo3(.*heced then
*lientData!et(.Pacet:ecords := !0in7dit(.9al)e
else
*lientData!et(.Pacet:ecords := O(/
*lientData!et(.*lose/
*lientData!et(.,0en/
end/

No ,nChan/e do SpinEdit tambm mudamos essa configurao:

procedure &'rm1ain.!0in7dit(*hange+!ender: &,b-ect./
begin
*lientData!et(.Pacet:ecords := !0in7dit(.9al)e/
end/

No boto !et*e-t(ac0et chamamos o mtodo de mesmo nome do ClienDataSet:

procedure &'rm1ain.BitBtn(*lic+!ender: &,b-ect./
begin
*lientData!et(.=etNe3tPacet/
end/

No Chec0Bo- com o nome de Fetch,nDemand configuramos a propriedade de mesmo do
ClienDataSet:

procedure &'rm1ain.*hecBo3A*lic+!ender: &,b-ect./
begin
BitBtn(.7nabled := not *hecBo3A.*heced/
*lientData!et(.'etch,nDemand := *hecBo3A.*heced/
end/

No Chec0Bo- usar (ac0et4ecords fazemos alguns ajustes visuais:

procedure &'rm1ain.*hecBo3(*lic+!ender: &,b-ect./
var
i : integer/
begin
=ro)0Bo3(.7nabled := *hecBo3(.*heced/
#abel(.7nabled := *hecBo3(.*heced/
!0in7dit(.7nabled := *hecBo3(.*heced/
*hecBo3A.7nabled := *hecBo3(.*heced/
BitBtn(.7nabled := +*hecBo3(.*heced. and not +*hecBo3A.*heced./
end/

No evento ,nLo/$race do SQLMonitor vamos monitorar a comunicao com o IB/FB para
verificar quando e quais comandos esto sendo executados, jogando essas informaes para
um Memo:

procedure &'rm1ain.!"#1onitor(#og&race+!ender: &,b-ect/
*BIn5o: 0!"#&:<*7Desc./
begin
1emo(.#ines.<dd+!tring+*BIn5o.0s?&race../
end/

Vamos executar a aplicao e fazer alguns testes, usando diferentes configuraes. Dessa
forma, vamos entender exatamente como o (ac0et4ecords funciona.

1 - Se+ usar Pa(=etRe(ords - clique no boto 4efresh e veja o comportamento na figura a
seguir. Todos os dados retornados pelo Select foram empacotados e jogados na memria
(Data) do ClienDataSet. Nenhum recurso do servidor, incluindo conexo e cursor, fica preso.
No entanto, o tempo necessrio e trfego de rede usado para transferir o packet maior.

Figura 2.
2 - Usando Pa(=etRe(ords (o+ 5et(*OnDe+and at%)ado - clique no boto 4efresh e veja
o comportamento na figura a seguir. Configuramos o packet size como "3, o que indica que os
registros sero empacotados de 3 em trs. O prprio ClientDataSet detecta quando mais
registros so necessrio e traz por demanda (da o nome Fetch,nDemand). Isso pode
acontecer tanto por necessidade do usurio (confirme isso navegando no DBGrid para baixo)
ou programaticamente (via chamadas subseqentes ao mtodo *e-t). Observe que cada Fetch
envolve, lgico, uma chamada ao servidor SQL. A soluo mais otimizada para grandes
resultsets, mais vai consumir mais recursos do BD, pois o cursor e conexo ficam presos
aguardando novas solicitaes de packet.

Figura 3.
3 - Usando Pa(=etRe(ords (o+ 5et(*OnDe+and desat%)ado - clique no boto 4efresh e
veja o comportamento na figura a seguir. Configuramos o packet size como "3, o que indica
que os registros sero empacotados de 3 em trs. A diferena em no usar o Fetch,nDemand
que voc deve solicitar novos pacotes de dados, atravs do mtodo !et*e-t(ac0et do CDS
(fizemos isso no boto). Faa um teste navegando at o ltimo registro do DBGrid, observe
que ele "trava no terceiro. Clicando no boto !et*e-t(ac0et, mais trs registros sero
trazidos. Cada Fetch envolve, lgico, uma chamada ao servidor SQL. A soluo mais
otimizada para grandes resultsets, mais vai consumir mais recursos do BD, pois o cursor e
conexo ficam presos aguardando novas solicitaes de packet.

Figura 4.
Parte <,I Sa)e Po%nt
Neste artigo veremos como usar o interessante recurso de Sa)e(oint do ClientDataSet. Esse
recursos permite que voc "tire um foto do atual status da memria do ClientDataSet, e
recupere este status a qualquer momento. Voc pode, por exemplo, salvar as atuais alteraes
do CDS em memria, fazer novas alteraes e a seguir desfaze-las, voltando ao estado original
previamente sinalizado. Imagine isso como uma espcie de transaes em memria, com
4ollbac0 e Commit. Para ver como isso funciona na prtica, preparei um exemplo interessante.
Coloque os componentes no formulrio conforme mostrado na figura a seguir. Aqui colocamos
um ClientDataSet. um DataSo%rce e trs B%ttons. D um clique de direita no ClientDataSet,
escolha Load from MyBase $able e abra o arquivo C%stomer.XML. localizado nos demos do
Delphi, por padro no diretrio C#8Ar9%i)os de pro/ramas8Ar9%i)os com%ns8Borland
Shared8Data. Arraste os $Fields para o form para criar os controles Data-Aware.

Figura 1.
O c&di$o D'( do )orm * mostrado a se$uir%

object *lientData!et(: &*lientData!et
<ctive = &r)e
ob-ect *lientData!et(*)stNo: &'loat'ield
'ieldName = 2*)stNo2
end
object *lientData!et(*om0any: &!tring'ield
'ieldName = 2*om0any2
!i?e = $;
end
object *lientData!et(<ddr(: &!tring'ield
'ieldName = 2<ddr(2
!i?e = $;
end
object *lientData!et(<ddrA: &!tring'ield
'ieldName = 2<ddrA2
!i?e = $;
end
object *lientData!et(*ity: &!tring'ield
'ieldName = 2*ity2
!i?e = (N
end
object *lientData!et(!tate: &!tring'ield
'ieldName = 2!tate2
end
object *lientData!et(Qi0: &!tring'ield
'ieldName = 2Qi02
!i?e = (;
end
object *lientData!et(*o)ntry: &!tring'ield
'ieldName = 2*o)ntry2
end
object *lientData!et(Phone: &!tring'ield
'ieldName = 2Phone2
!i?e = (N
end
object *lientData!et('<L: &!tring'ield
'ieldName = 2'<L2
!i?e = (N
end
object *lientData!et(&a3:ate: &'loat'ield
'ieldName = 2&a3:ate2
end
object *lientData!et(*ontact: &!tring'ield
'ieldName = 2*ontact2
end
object *lientData!et(#astInvoiceDate: &Date&ime'ield
'ieldName = 2#astInvoiceDate2
end
end
object Data!o)rce(: &Data!o)rce
Data!et = *lientData!et(
end
object DB=rid(: &DB=rid
Data!o)rce = Data!o)rce(
end
object DBNavigator(: &DBNavigator
Data!o)rce = Data!o)rce(
end

O cdigo do boto Sa)e(oint salve o estado atual do ClientDataSet:

procedure &'rm1ain.BitBtnA*lic+!ender: &,b-ect./
begin
1yPoint := *lientData!et(.!avePoint/
end/

MyPoint uma varivel declara no form, com o seguinte tipo:

public
1yPoint : integer/

Para recuperar o estado, basta atribuir novamente essa propriedade ao Sa)e(oint, observe
(fizemos isso no outro boto):

procedure &'rm1ain.BitBtn$*lic+!ender: &,b-ect./
begin
*lientData!et(.!avePoint := 1yPoint/
end/

Para voltar ao ltimo estado, chamamos o UndoLastChanges no boto de mesmo nome:

procedure &'rm1ain.BitBtn(*lic+!ender: &,b-ect./
begin
*lientData!et(.Undo#ast*hange+tr)e./
end/

Executando a aplicao, vamos fazer alguns testes para ver como recurso funciona. Altere o
Company colocando "TESTE1 ao final, clique em (ost no DB*a)i/ator e a seguir no boto
Sa)e(oint. Seguindo os mesmos passos, altere para "TESTE2 e "TESTE3, dando sempre um
post e savepoint ao final.

Figura 2.
Agora clique vrias vezes no boto 1nLastChan/es e verifique que o estado atual de cada
savepoint recuperado a cada chamado a mtodo, como transaes de BD, porm, tudo em
memria.
Parte <,II Re(ord Count e Re(No
Neste artigo veremos como usar as propriedades 4ecordCo%nt e 4ec*o do ClienDataSet. Essas
propriedades so exclusivas desse componente, sendo que possuam capacidades limitadas
quando se trabalhava com BDE. 4ecordCo%nt, por exemplo, sempre retornava -1 em Queries
de consultas a banco de dados quando se usa o BDE. Essa limitao no existe no
ClientDataSet, pois o mesmo possui todas as informaes em memria.
4ecordCo%nt - retorne o nmero atual de registros na memria do ClientDataSet,
ou seja, o nmero de registros retornados pelo Select associado (a menos que se use
(ac0et 4ecords).
4ec*o - a posio atual do cursor local de dados na memria do ClientDataSet. Por
exemplo, se esse valor for "5, estamos navegando no quinto registro do
ClientDataSet.
Vejamos como isso funciona na prtica. Coloque os componentes no formulrio conforme
mostrado na figura a seguir. Aqui colocamos um ClientDataSet. um DataSo%rce, um DB!rid.
um B%tton e um Label. D um clique de direita no ClientDataSet, escolha Load from MyBase
$able e abra o arquivo C%stomer.XML. localizado nos demos do Delphi, por padro no diretrio
C#8Ar9%i)os de pro/ramas8Ar9%i)os com%ns8Borland Shared8Data.

Figura 1.
No boto simplesmente jogamos o valor de 4ecordCo%nt no Caption do Label.

procedure &'rm1ain.BitBtn(*lic+!ender: &,b-ect./
begin
#abel(.*a0tion := Int&o!tr+*lientData!et(.:ecord*o)nt./
end/

Tambm criamos um campo calculado no ClientDataSet, como mostrado a seguir. Ele do tipo
Inte/er e vai indicar a posio atual do registro no resulset, se comportando como se fosse um
campo normal do BD (como cdigo, ID etc.)

Figura 2.

Figura 3.

No ,nCalcFields atribumos o valor do campo com base no valor do 4ec*o atual do
ClientDataSet:

procedure &'rm1ain.*lientData!et(*alc'ields+Data!et: &Data!et./
begin
*lientData!et(:7*N,.<sInteger :=
*lientData!et(.:ecNo/
end/

Observe ambos 4ecordCo%nt e 4ec*o em ao na figura a seguir.

Figura 4.
Voc tambm pode fazer um DB!rid "zebrado usado o 4ec*o, bastando verificar se o ndice
do registro mpar o par. Isso no possvel no BDE, pois sempre retorna -1. Isso pode ser
feito com o seguinte cdigo no evento ,nDra2Col%mnCell do DB!rid:

procedure &'rm1ain.DB=rid(Draw*ol)mn*ell+!ender: &,b-ect/
const :ect: &:ect/ Data*ol: Integer/ *ol)mn: &*ol)mn/
!tate: &=ridDraw!tate./
begin
(*DBGrid zebrado*)
if not odd+*lientData!et(.:ecNo. then KK se 5or Tm0ar
if not +gd!elected in !tate. then KK se a cUl)la n4o estV selecionada
begin
DB=rid(.*anvas.Br)sh.*olor:= clJellow/ KK de5ine )ma cor de 5)ndo
DB=rid(.*anvas.'ill:ect+:ect./ KK 0inta a cUl)la
DB=rid(.De5a)ltDrawData*ell+rect@*ol)mn.'ield@!tate./ KK 0inta o te3to 0adr4o
end/
end/

O resultado mostrado na figura a seguir:

Figura 5.
Parte <I< Usando %nter>a(es
Em DataSnap e qualquer arquitetura de objetos distribudos, faz-se uso intensivo de
interfaces. importantssimo que voc saiba e compreenda como feita a comunicao entre
cliente e servidor de aplicao, atravs do uso desse recurso. Interfaces so usadas
amplamente nos bastidores de um arquitetura DataSnap.
Dessa forma, decido incluir um captulo introdutrio neste curso, que mostra como usar
interfaces "puras (no relacionadas ao DataSnap, mas a POO). Entendendo o princpio bsico
aqui proposto, ser base para entendermos abordagens mais complexas quando estudarmos o
COM, MTS, COM+ e SOAP.
Uma interface semelhante a uma classe que possua somente mtodos abstratos, ou seja,
sem implementao. Uma interface apenas define mtodos que depois devem ser
implementados por uma classe. Dessa forma, um objeto pode se comunicar com o outro
apenas conhecendo a sua interface, que funciona como uma espcie de contrato.

Figura 1.
Uma interface como se fosse um controle remoto. Voc consegue interagir com um objeto
conhecendo o que ele oferece, tendo a interface que descreve cada funo, porm, sem a
mnima idia de como ele implementa essa funcionalidade internamente.
Assim como $,bect a classe base para todas as classes do Delphi, a interface base para
todas as interfaces IInter>a(e. A interface base para todos as interfaces COM IUn=no"n.
I1n0no2n na verdade apenas um alias para IInterface.

Uma Interface no tem cdigo de implementao associado.

Aten!o - O uso de Interfaces um recurso da linguagem Delphi, de forma que voc poder
utilizar interfaces mesmo que no esteja programando objetos distribudos.

Veja a seguir a declarao de IInterface:

IInter5ace = interface
[2F;;;;;;;;O;;;;O;;;;O*;;;O;;;;;;;;;;DRG2]
function ")eryInter5ace+const IID: &=UID/ out ,b-.: P:es)lt/ stdcall/
function _<dd:e5: Integer/ stdcall/
function__:elease: Integer/ stdcall/
end/

Os mtodos 7Add4ef e 74elease definem o mecanismo de conta/em de refer:ncia. Isso
significa que voc no precisa liberar um objeto que implementa IInterface. Q%eryInterface faz
solicitaes dinamicamente um objeto para obter uma referncia para as interfaces que ele
suporta.

Para demonstrar o uso de interfaces vamos criar um pequeno exemplo. Inicie uma nova
aplicao no Delphi. Salve o formulrio como "uFrmMain.pas e o projeto "Interfaces.dpr. D
o nome de "FrmMain ao formulrio.
Abra a unit do formulrio e declara a seguinte interface na seo type.

type
I*alc = interface
function 1)lti0licar +const 3@y : integer. : integer/
end/

Note que no podemos apertar Shift+Ctrl+C e implementar o mtodo M%ltiplicar. Esse um
mtodo de interface, como um mtodo abstract de uma classe.
Logo abaixo da interface declare a seguinte classe:

&*om0)tador = class +&Inter5aced,b-ect@I*alc.
function 1)lti0licar +const 3@y : integer. : integer/
end/

&*alc)ladora = class +&Inter5aced,b-ect@I*alc.
function 1)lti0licar +const 3@y : integer. : integer/
end/

$Comp%tador = (#ass ($Interfaced,bect,ICalc) significa "$Comp%tador herda de
$Interfaced,bect e implementa a interface ICalc. Isso n!o herana mltipla.

Observe que ambas as classes $Comp%tador e $Calc%ladora implementam a interface ICalc, e
descendem de $Interfaced,bect. $Interfaced,bect se encarrega de implementar a interface
IInterface.
Aperte Shift+Ctrl+C para declarar os cabealhos dos mtodos.

function &*om0)tador.1)lti0licar+const 3@ y: integer.: integer/
begin
res)lt:=38y/
end/

function &*alc)ladora.1)lti0licar+const 3@ y: integer.: integer/
var
i : integer/
begin
res)lt:=;/
if +3WI;. and +yWI;. then
for i:=( to abs+y. do
res)lt:=res)ltH3/
end/

Observe que ambas as classes implementam o mtodo M%ltiplicar de ICalc, porm de formas
diferentes. Usando Edits. um 4adio!ro%p e um B%tton construa o seguinte formulrio:

Figura 2.
D um duplo clique no boto e digite:

procedure &'rm1ain.B)tton(*lic+!ender: &,b-ect./
var
,b- : I*alc/
n(@nA@r : integer/
begin
if :adio=ro)0(.ItemInde3=O( then e3it/
case :adio=ro)0(.ItemInde3 of
; : ,b-:=&*alc)ladora.create/
( : ,b-:=&*om0)tador.create/
end/
n(:=!tr&oInt+7dit(.&e3t./
nA:=!tr&oInt+7ditA.&e3t./
r:=,b-.1)lti0licar+n(@nA./
7dit$.&e3t:=Int&o!tr+r./
end/

Rode e teste a aplicao.

Figura 3.
Parte << Ob?etos CO/
Neste artigo, veremos como criar e como usar objetos COM, um dos fundamentos mais bsicos
da programao de objetos distribudos e DataSnap.
COM (Component ,bect Model) a tecnologia desenhada pela Microsoft que possibilita a
comunicao entre aplicaes clientes e aplicaes servidoras. Essa comunicao feita
atravs do que chamamos de interfaces. Uma interface COM a maneira como um objeto
expe sua funcionalidade ao meio externo. Um GUID (!lobally 1ni9%e Identifier) um nmero
utilizado no COM para identificar uma interface ou uma Co-Class. Quando utilizado para
identificar uma interface, um GUID tambm chamado de IID (interface ID).
Vamos ento criar nosso primeiro objeto COM. Siga os seguintes passos: Clique em File;*e2|
,ther. Na guia Acti)eX clique em Acti)eX Library. Uma nova biblioteca ser criada, que ser a
DLL que conter nosso objeto COM. Salve esta biblioteca com o nome de "LibExemplo.
Clique novamente em File;*e2;,ther. Na guia Acti)eX escolha agora C,M ,bect.

Figura 1.
Na caixa de dilogo que aparece, digite "Soma para o nome da classe. O Delphi
automaticamente preenche o nome da interface a ser implementada (ISoma). Deixe a opo
M%ltiple Instance como padro para Instancin/ (isso far com que uma nova instncia de
nosso objeto seja criada para cada aplicao cliente). Na opo $hreadin/ Model deixe o
padro Apartment (cada objeto COM executado dentro de seu prprio Thread).

Figura 2.
Clique em OK. Aparecer a $ype Library do objeto COM. Salve a unidade criada com o nome
de uSoma. Uma Type Library constitui a maneira de identificarmos os mtodos suportados por
uma interface. O Delphi oferece um editor onde se pode facilmente construir uma interface
para um objeto e atravs de cdigo Pascal implementar essa interface. Para visualizar o editor
da $ype Library de um objeto voc pode acessar o menu 3ie2;$ype Library.
No editor da $ype Library, d um clique de direita sobre a interface ISoma. Escolha *e2;
Method. D o nome de "Somar para o mtodo. Em nosso primeiro exemplo, criaremos um
funo que receber dois parmetro Sin/le, retornando a soma de ambos.
Na opo 4et%rn $ype da guia (arameters, escolha Sin/le. Clique em Add e insira dois
parmetros ("Num1 e "Num2) do tipo Sin/le. Salve tudo para o Delphi atualizar a unit de
implementao. Tenha em mente que OLE e COM no oferecem suporte a todos os tipos de
dados do Delphi.

Figura 3.
Clique agora em 3ie2;1nits e escolha LibE-emplo7$LB. Voc ver uma extensa unidade Pascal
que define a $ype Library da interface criada. Logo no incio h uma declarao avisando a
voc para no mudar este cdigo fonte. Qualquer modificao neste cdigo deve ser feita por
meio do editor da $ype Library.
Procure pela seguinte declarao:

I!oma = interface+IUnnown.
[2F'(D$(B(NODRDNODB*(OE'AROE(BSBB'EDD*SG2]
function !omar+N)m(: !ingle/ N)mA: !ingle.: single/ stdcall?
end/

Esta a definio da nossa interface feita anteriormente no editor da Type Library. O que
precisamos fazer agora codificar o mtodo Somar. Abra a unit %Soma e na seo
implementation implemente a funo (o Delphi j colocou os cabealhos).

function &!oma.!omar+N)m(@ N)mA: !ingle.: !ingle/
begin
res)lt:=N)m(HN)mA/
end/

Agora basta compilar a biblioteca. Clique em (roect;B%ild LibE-emplo. Clique em 4%n;4e/ister
Acti)eX Ser)er para registrar o objeto.
Vamos agora criar um cliente para nosso objeto COM criado anteriormente. Siga os passos
abaixo: Clique em File;*e2 Application. Salve a unit com o nome de "uClienteCOM.pas e o
projeto com o nome de "ClienteCOM.dpr. D o nome de "FrmMain e Caption "Objetos COM
ao formulrio. Coloque um boto no formulrio, com o Caption "Somar, e trs Edits. Veja a
figura:

Figura 4.
O objetivo agora clicar no boto e chamar a funo Somar de nosso objeto COM, definido por
nossa interface ISoma, implementada em nossa Co-Class $Soma. Para isso precisamos
importar a $ype Library do objeto que queremos instanciar.
Clique em (roect;Add to (roect e localize o arquivo LibE-emploLib7$LB. Isso faz com que a
$ype Library da interface ISoma seja incorporada ao nosso aplicativo. Mas veja bem, apenas a
interface do objeto ser conhecida por ns, pois a sua implementao ficar oculta. Ns
saberemos que ISoma possui o mtodo Somar mas no sabemos como ela realiza o
processamento internamente.
Agora no formulrio principal clique em File;1se 1nit e escolha LibE-emplo_TLB. Faa o
seguinte no evento ,nClic0 do boto:

procedure &'rm1ain.B)tton(*lic+!ender: &,b-ect./
var
,b- : I!oma/
n(@nA@n$ : single/
begin
,b-:=*o!oma.*reate/
n(:=!tr&oInt+7dit(.&e3t./
nA:=!tr&oInt+7ditA.&e3t./
n$:=,b-.!omar+n(@nA./
7dit$.te3t:='loat&o!tr+n$./
end/

Execute e veja o resultado como na figura abaixo:

Figura 5.
Caso o servidor no tenha sido registrado uma exceo do tipo E,leSysError levantada com
a mensagem "Classe no registrada.
Parte <<I Ser)%dores de Ap#%(a!o e Re+ote Data /odu#es
Utilizamos o DataMod%le para separar o cdigo de acesso a dados da interface de usurio. no
DM que utilizamos os $DataSets, como a $SQLQ%ery e a $SQL$able, alm do componente
$SQLConnection. Esses componentes so responsveis pela comunicao com o banco de
dados (SGBDR). No DM geralmente tambm so implementados procedures que fazem
validao sobre alguns dados, introduzem um campo padro ou um campo calculado. Quando
compilamos nossa aplicao, todo o cdigo de acesso, clculos e regras ficaro residentes em
nosso executvel. Se por algum motivo for necessrio mudar algum parmetro de consulta,
alguma instruo SQL, um campo $Field, uma mscara, alguma regra de dados, precisaremos
recompilar toda a aplicao. E isso no tudo: os componentes dbExpress usam bibliotecas
.dll que devem ser colocadas em todas as mquinas da rede que acessar o banco. Tambm
devemos instalar e configurar os conhecidos SQL Clients (clientes de banco SQL), que so
bibliotecas especficas para cada SGBDR. Uma soluo separar o acesso em um 4emote
DataMod%le.

O 4emote DataMod%le nada mais do que um servidor COM, que basicamente tem a mesma
funo de um DM, porm pode fazer uso dos recursos do DCOM. A grande vantagem de se
usar um RDM que ele pode ficar totalmente separado do executvel principal da aplicao
cliente, residindo em um outro processo, em um outro computador. Surge ento mais uma
camada em nosso sistema. Temos a o que se chama de uma aplicao 3 camadas : o cliente,
o RDM (constituindo o servidor de aplicao) e o servidor de dados (SGBDR). As aplicaes
desenvolvidas utilizando esse tipo de tecnologia tambm so conhecidas como aplicaes
M%lti$ier (Multicamadas).



Figura1. Remote DataModule
Aqueles procedures que colocamos em nosso antigo DM agora sero implementados dentro de
nosso servidor DCOM (o RDM). O cliente conhecendo a interface do nosso objeto DCOM pode
ento fazer chamadas a esses procedimentos residentes no RDM, atravs de uma RPC
(4emote (roced%re Call) usada pelo DCOM. O mecanismo que possibilita que clientes faam
chamadas a funes de objetos residindo em um diferente processo ou em uma diferente
mquina se chama marshalin/.
O RDM ser responsvel por gerenciar o acesso aos dados e as regras de negcio - chamadas
B%siness 4%les (todas as validaes, imposies, clculos, constraints e acessos que envolvem
os dados de uma aplicao). Os componentes de acesso do Delphi (BDE, ADO ou IBX)
precisam estar somente no servidor de aplicao.

As bibliotecas de clientes SQL tambm no sero necessrias em cada mquina cliente,
somente no servidor de aplicao. O cliente s precisa levar consigo a biblioteca dbclient.dll se
for feito em Delphi 4 e Midas.dll se feito em Delphi 5 ou superior. Todas as aplicaes clientes
acessam a mesma camada (middle< tier), evitando redundncia de regras de negcio, que
ficam encapsuladas em uma nica camada compartilhada. As aplicaes clientes ento contm
no muito mais do que a interface com o usurio. Para o usurio final uma aplicao MultiTier
no muito diferente de uma aplicao tradicional cliente-servidor. Os clientes passam a fazer
apenas alguma manipulao de tela e alguma chamadas ao servidor de aplicao (por esse
motivo so chamados Thin Clients). Os clientes NUNCA se comunicam diretamente com o
servidor de banco de dados.
Cr%ando u+ Ser)%dor de Ap#%(a!o DCO/
Comece uma nova aplicao em Delphi clicando em File;*e2|Application. Salve a unit com o
nome de "uFrmMain.pas e o projeto como "AppServerDCOM.dpr. D o nome de "FrmMain ao
formulrio, caption de "Servidor DCOM Ativado e reduza o seu tamanho. Coloque-o no canto
inferior direito da tela. Este formulrio apenas indicar que o servidor DCOM est ativado.


Figura. Formulrio principal do servidor DCOM
Agora clique em File|New|Other. No Object Repository, na guia MultiTier, escolha Remote
DataModule.


Figura. Criando um Remote DataModule
Na caixa de dilogo que aparece, digite "RDM para o nome da Co<Class. Deixe as opes
Instancin/ e $hreadin/ Model como esto (estas so as mesmas opes disponveis quando
criamos um objeto COM no primeiro exemplo). Salve a unit criada como "uRDM.pas.
Coloque um componente SQLConnection e configure o acesso ao banco EMPLOYEE.GDB do
Interbase, normalmente situado em "C:\Arquivos de programas\Arquivos Comuns\Borland
Shared\data\employee.gdb. Defina seu Lo/in(rompt como False e Connected como $r%e.


Figura. Conectando ao Interbase a partir do Remote DataModule
Coloque um SQLDataSet apontando para o SQLConnection e na sua propriedade CommandText
di$ite%

select 8 fro/ *U!&,17:

Coloque no RDM o componente $DataSet(ro)ider (paleta DataAccess=. Aponte sua propriedade
DataSet para SQLDataSet. Voc deve usar um componente $DataSet(ro)ider para cada
$DataSet que utilizar no RDM.
Vamos tambm incluir um procedure em nosso servidor, que ser chamado remotamente pelo
cliente, que ter a funo de verificar se um determinado CPF vlido (note que a validao -
uma regra de negcio - ficar totalmente separada do cliente, e se ela mudar, no
precisaremos recompilar ou reinstalar clientes, alm do processamento de clculo da regra ser
totalmente feito no servidor de aplicao). Importante: no confunda isso com um Stored
(roced%re dos servidores SQL que algo totalmente diferente.
Abra o editor da $ype Library clicando em 3ie2;$ype Library. D um clique de direita no editor
e escolha *e2;Method. D ao mtodo o nome de 3erificaC(F. Clique na guia (arameters e
adicione um parmetro chamado CPF do tipo 5ideStrin/.


Figura. Criando um mtodo no editor da Type Library
Abra a unit uRDM e localize a declarao da funo 3erificaC(F. Implemente a funo da
seguinte forma:

procedure &:D1.9eri5ica*P'+const *P': >ide!tring./
var
d(@dA@n(@nA@na@loo0 : integer/
begin
na:=(/
for loo0:=( to #ength+*P'.OA do
begin
n(:=n(H+((Ona.8!tr&oInt+*P'[loo0]./
nA:=nAH+(AOna.8!tr&oInt+*P'[loo0]./
na:=naH(/
end/
d(:=;/
if +n( /od ((.I=A then
d(:=((O+n( /od ((./
dA:=;/
nA:=nAHA8d(/
if +nA /od ((.I=A then
dA:=((O+nA /od ((./
if +inttostr+d(.WI*P'[(;]. or
+inttostr+dA.WI*P'[((]. then
raise 73ce0tion.*reate+2*P' InvVlido2./
end/

Pressione F9 para compilar, registrar e executar o servidor DCOM. Na prxima parte deste
curso construiremos a aplicao cliente.
Parte <<II C#%entes DataSnap
Neste artigo, veremos como construir uma aplicao cliente que far acesso ao servidor de
aplicao criado na parte anterior deste curso. Tambm conheceremos mais alguns detalhes
envolvidos na construo de aplicaes DataSnap e multicamadas.
U+ T*%n C#%ent
Clique em File;*e2;Application. Salve a unit com o nome de "uFrmMain.pas e o projeto com o
nome de "DataSnapClient.dpr. D ao formulrio o nome de FrmMain e caption de "DataSnap
Client. Crie um DataMod%le clicando em File;*e2;DataMod%le. Salve sua unit como "uDM.pas
e d a ele o nome de "DM.
Coloque no DM um componente $DC,MConnection da guia DataSnap. Na propriedade
Ser)er*ame escolha nosso servidor de aplicao registrado, chamado neste caso de
AppSer)erDC,M.4DM.


Figura. Configurando ServerName do DCOMConnection
Configure a propriedade Connected para $r%e. A janela principal do servidor de aplicao deve
aparecer neste momento. Coloque um componente ClientDataSet. Configure sua propriedade
4emoteSer)er para o DC,MConnection. Na propriedade (ro)ider*ame escolha o
DataSet(ro)ider (que est no RDM, que por sua vez aponta para o SQLDataSet de
C%stomers). Configure a propriedade Acti)e para $r%e. Os dados da tabela CUSTOMERS sero
trazidos do servidor de aplicao. D um duplo clique no ClientDataSet e adicione todos os
campos $Fields. Seu DM deve estar como mostrado a seguir.


Figura. DataModule da aplica!o cliente
Pro)%d%n-
Quando o ClientDataSet recebe os dados vindos do servidor de aplicao, os mesmos so
decodificados, pois vieram empacotados em formato ,LE3ariant. No servidor de aplicao, o
DataSet(ro)ider se encarrega de distribuir os dados empacotados aos clientes, numa
operao chamada pro)%d%n-. Voc pode incluir dados personalizados neste pacote se quiser,
como hora do sistema, usando o evento ,n!etDataSet(roperties do DataSet(ro)ider.
5or+u#@r%o pr%n(%pa#
Volte ao formulrio principal. Aperte Alt+F11 e na lista escolha uDM. Coloque um DataSo%rce
da guia DataAccess e na propriedade DataSet aponte para o ClientDataSet que est no DM.
Usando DBEdits e Labels (alm de um DB*a)i/ator) construa o formulrio mostrado a seguir:


Figura. "#in$Client DataSnap
Coloque um B%tton, d o caption de "Apply e no evento ,nClic0 digite o seguinte :

D1.*lientData!et.<00lyU00dates+O(./
Reso#)%n- e Re(on(%#e
Apply1pdates aplica a cache do ClientDataSet (chamada DELTA) no servidor de aplicao. O
servidor de aplicao ir tentar aplicar a cache recebida no servidor de banco de dados por
meio do componente DataSet(ro)ider (reso#)%n-). Se algum erro for constatado, o servidor
de aplicao devolve os dados ao cliente, para que sejam manipulados no evento
,n4econcileError do ClientDataSet.
C*a+ando o +'todo de ne-:(%o
Coloque um boto no formulrio (com o caption "CPF) e no seu evento ,nClic0 digite:

procedure &'rm1ain.B)ttonA*lic+!ender: &,b-ect./
var
*P' : string/
begin
*P':=In0)tBo3+2*hamando mUtodo remoto2@2")al o nX do se) *P'Y2@22./
D1.D*,1*onnection.<00!erver.9eri5ica*P'+*P'./
!how1essage+2*P' vVlido2./
end/

Pressione F9 para executar a aplicao cliente. Insira alguns registros. Teste a validao do
CPF. No esquea de pressionar Apply depois de gravar um registro, caso contrrio, a cache
(delta) no ir para o servidor de aplicao e seus dados no sero realmente gravados no
servidor de banco de dados. A chamada ao mtodo Apply1pdates do ClientDataSet dispara o
evento ,n1pdateData e Before1pdate4ecord do DataSet(ro)ider no servidor de aplicao,
onde voc pode trocar alguns valores, decodificar dados, inserir novos valores antes dos dados
serem realmente aplicados no banco.
Sa>eCa##
Observe que demos um ra%se no servidor de aplicao quando um CPF for invlido. Essa
exceo entretanto no levantada no servidor de aplicao, o que poderia ser fatal. Observe
a declarao do mtodo 3erificaC(F:

procedure 9eri5ica*P'+const *P': >ide!tring./ safecall/

Sa>eCa## a diretiva que protege uma mtodo contra excees. Qualquer exceo que for
levantada dentro da pilha da chamada do mtodo ser propagada para a aplicao cliente.
A %nter>a(e IAppSer)er
Neste cliente usamos a vinculao dinmica com o servidor de aplicao, atravs do uso da
propriedade AppSer)er. Como AppServer do tipo 3ariant, o Delphi no pode verificar na
compilao se o mtodo 3erificaC(F realmente existe no servidor de aplicao. Isto feito em
tempo de execuo (vnculo dinmico). Experimente digitar "VerCPF e nada acontece at o
mtodo ser finalmente chamado. Se um mtodo no encontrado no servidor uma exceo do
tipo E,leError gerada:


Figura. %&nculo din'mico ( c#amadas s!o resolvidas em tempo de e)ecu!o
Poderamos ter usado vnculo esttico (importando a $ype Library) da mesma forma como
fizemos no primeiro exemplo, para que o compilador, j em design-time, identifica-se os
mtodos suportados pela nossa interface I4DM (observe tambm que nossa interface I4DM
derivada da interface IAppSer)er).
AppSer)er propriedade de $DispatchAppSer)er, que uma das classes base de
$DC,MConnection. $DispatchAppSer)er implementa os mtodos definidos por IAppSer)er.

Parte <<III Introdu!o ao CO/A
Como vamos, um dos problemas do DCOM a sua escalabilidade. Isto , ele no apresenta os
mesmo resultados quando h um aumento do nmero de conexes, perdendo desempenho.
Objetos DCOM mantm informaes persistentes sobre cada cliente que instancia um objeto
do seu tipo, e s ir liberar tais recursos quando a varivel sair do escopo no programa cliente.
Devido aos objetos DCOM permanecerem ativos com informaes sobre o cliente e sua
ativao, so conhecidos como objetos com estado.
O sucessor do DCOM foi o MTS (Microsoft $ransaction Ser)er). Ele incorporou diversos
recursos a essa tecnologia. O MTS instalado como parte do Windows NT 4 Server (,ption
(ac0). Diferente do DCOM que no possui um gerenciador prprio (a no ser o pequeno
DCOMCNFG.EXE), o MTS utiliza o MMC (Microsoft Mana/ement Console) para configurar e
gerenciar objetos. O COM + o sucessor do MTS (mais o MSMQ - Microsoft Messa/e Q%e%e),
e herda deles inmeros recursos: gerenciamento centralizado, pooling de objetos, suporte a
transao e escalabilidade.
O COM+ acompanha o Windows 2000/XP, formando a chamada camada lgica de negcio em
um sistema Distribudo (Multicamadas).


Figura. COM * atuando na camada l+gica de neg+cio em uma ar,uitetura distribu&da
Cr%ando (o+ponentes CO/A
Clique em File|New|Active X|Tranactional O!"ect.


Figura. Criando um ob-eto COM*
Na caixa de dilogo que aparece digite "Soma para CoClas *ame.


Figura. Op.es de cria!o de um ob-eto COM*
Pressione File|Sa)e All e salve a unit como "uSoma.pas e o projeto como "LibSoma.dpr. Da
mesma forma que fizemos para o objeto COM criado neste mesmo mdulo, crie um mtodo
chamado Somar que aceite dois parmetros do tipo Sin/le.


Figura. /ditor da "0pe 1ibrar0
Implemente a funo na unit da seguinte forma:

function &!oma.!omar+3@ y: !ingle.: !ingle/
begin
res)lt:=3Hy/
end/

Clique em Project|Build LibSoma.
T/tsAutoOb?e(t
A classe $MtsA%to,bect encapsula objetos e interfaces de um servidor de aplicao MTS.

&!oma = class+&1ts<)to,b-ect@ I!oma.
protected
function !omar+3@ y: !ingle.: !ingle/ safecall/
end/

&1ts<)to,b-ect = class+&<)to,b-ect@ I,b-ect*ontrol.
private
',b-ect*onte3t: I,b-ect*onte3t/
'*anBePooled: Boolean/
protected
F I,b-ect*ontrol G
procedure <ctivate/ safecall/
procedure Deactivate/ stdcall/
function *anBePooled: Bool/ virtual/ stdcall/

procedure ,n<ctivate/ virtual/
procedure ,nDeactivate/ virtual/
property ,b-ect*onte3t: I,b-ect*onte3t read ',b-ect*onte3t/
public
procedure !et*om0lete/
procedure !et<bort/
procedure 7nable*ommit/
procedure Disable*ommit/
function IsIn&ransaction: Bool/
function Is!ec)rity7nabled: Bool/
function Is*allerIn:ole+const :ole: >ide!tring.: Bool/
property Pooled: Boolean read '*anBePooled write '*anBePooled/
end/
Insta#ando o ser)%dor CO/A
Voc pode instalar o objeto COM+ de duas formas:
Usando o gerenciador MMC chamado Ser)i>os de Componente
Usando a opo Install C,M? ,bects disponvel na IDE do Delphi.
Usaremos a segunda opo. Clique em 4%n;Install C,M? ,bects.


Figura. Instalando um servidor COM*
Preencha as opes como mostra a figura a seguir.


Figura. Instalando um servidor COM*
Aten!o& Quando voc instala a aplicao no catlogo do COM+ ela estar automaticamente
registrada.
Cr%ando o (#%ente
Clique em File;*e2;Application. Clique em File;Sa)e All e salve a unit como "uCliSoma.pas e a
aplicao como "CliSoma.dpr. Clique em (roect;Add to (roect e adicione o arquivo
LibSoma7$LB.pas, que a $ype Library do servidor criado anteriormente. No formulrio
principal aperte ALT+F11 e adicione a TLB clusula uses. No evento ,nClic0 do boto digite:

7dit$.te3t:='loat&o!tr+*o!oma.*reate.!omar+
!tr&oInt+7dit(.&e3t.@!tr&oInt+7ditA.&e3t.../


Figura. Cliente para um servidor COM*
Parte <<I, CO/A e DataSnap
Nesta parte do curso, veremos como utilizar DataSnap integrado ao COM+, a soluo mais
indicada para a construo de aplicaes de BD multicamadas.
DataSnap no /TSBCO/A
No Delphi 7, clique em File|*e2|,ther. No ,betct 4epository, na guia M%lti$ier, clique sobre
$ransactional Data Mod%le.


Figura. Cliente para um servidor COM*
Digite "RDM para o nome da Co-Class e deixe as demais opes como padro. Salve o projeto
como "AppServerCOMPlus.dpr. Configure o DataMod%le usando os mesmos componentes do
exemplo anterior, como mostrado a seguir:


Figura. Conectando ao Interbase a partir do Remote DataModule
Clique em (roect;B%ild AppSer)erCom(l%s.
Ser)%os de Co+ponentes - Insta#ando o ob?eto CO/A
Ao invs de utilizaremos a IDE do Delphi para instalar o objeto agora vamos usar o Ser)i>os
de Componente. Clique em Iniciar;(ainel de Controle;Ferramentas Administrati)as;Ser)i>os de
Componente. Expanda o item Ser)i>os de componente e clique de direita sobre Aplicati)os
C,M?.


Figura. Criando um novo aplicativo no COM*
Na janela que aparece clique em *e-t. Depois clique em Criar %m aplicati)o )a@io.


Figura. Criando um novo aplicativo no COM*
D o nome de "AppServerCOMPlus ao aplicativo. Depois clique em A)an>ar e Concl%ir.
Expanda o novo aplicativo criado e d um clique de direita em Componentss. e escolha *o)o
Componente. Clique em A)an>ar e depois escolha Instalar no)oAs= componenteAs=.


Figura. Instalando um componente no aplicativo no COM*
Localize a DLL da aplicao servidora criada anteriormente no Delphi (AppSer)erCom(l%s.dll).
Clique em A)an>ar e Concl%ir.
Veja na figura a seguir nosso componente instalado no catlogo do COM+.


Figura. Componente instalado no COM*
T*%n-C#%ent para o ser)%dor CO/A
Agora usaremos o mesmo cliente construdo para o servidor DCOM construdo anteriormente,
chamado DataSnap Client. Aps abrir o projeto v at o DM e adicione um segundo
DC,MConnection. dando a ele o nome de "MTSConnection.
Altere sua propriedade Ser)er*ame para apontar para o novo servidor COM+. Defina o
4emoteSer)er do ClientDataSet como M$SConnection. Reconecte o ClientDataSet.


Figura. Configurando o ServerName do DCOMConnection
Des#%-ando e In%(%ando pa(otes
Para retirar a DLL da memria do servidor e parar um pacote, basta que voc d um clique de
direita na aplicao e escolha Desli/ar. Para reiniciar escolha a opo 4einiciar. Lembre-se que
o COM+ B%st<In<$ime Acti)ation, logo o pacote ser carregado assim que um cliente
instanciar um objeto. Se voc escolher a opo Desati)ar, ento o pacote no ser carregado
automaticamente a menos que algum o inicie.


Figura. Desligando e reiniciando um pacote COM*
Parte <<, SOAP e CebSer)%(es Ap#%(a7es Ser)%doras
At agora vimos que a tecnologia COM permite que objetos sejam distribudos em uma rede
local. Porm o COM possui algumas limitaes:
um padro proprietrio;
No multi-plataforma;
Apresenta problemas em rede com firewalls;
SOAP
Simple ,bect Access (rotocol - mecanismo que permite a troca de mensagens entre
servidores e clientes.
Padro aberto;
Roda no topo do protocolo HTTP;
Dados trafegam em XML;
Multi-plataforma;
Ceb Ser)%(es 2BDC )s BDB3
Quando voc precisa consultar a cotao on-line do dlar, voc geralmente abre um browser e
acessa um determinado site que fornea a cotao em tempo real. Se voc precisa consultar o
CEP de uma pessoa, precisa abrir um browser e entrar no site dos correios. Se precisar
consultar a disponibilidade de vos de uma empresa rea, precisa entrar em seu site. Ou seja,
tudo feito por um browser (cliente) acessando um servio (business).
BDC

Browser HTTP/
HTML Servidor
Figura. 2plica!o 3usiness to Consumer 435C6
Uma aplicao B2B (Business to Business), ao invs de distribuir dados em formato HTML,
distribui dados em formato XML. Isso permite que outras aplicaes (que no somente um
browser) possam se comunica com esse servio e retirar dele informaes. Essas informaes
podem ser colocadas em um formulrio do Delphi, do Visual Basic, do Kylix, em uma pgina
PHP, em uma planilha do Excel, etc.
Isso , voc desenvolvedor (um lado do negcio) utiliza servios de outra empresa (o outro
lado) para disponibilizar informaes para o seu cliente final. Ex.: Uma agncia de turismo
desenvolve uma HomePage para que os usurios possam agendar viagens pelo mundo inteiro.
Porm, a empresa gostaria de oferecer um pacote completo, incluindo dirias de hotel,
pesquisa de preos em companhias areas, disponibilizada de transporte na cidade,
alimentao, etc. Para isso, um atendente teria que entrar no site de cada um das empresas,
anotar horrios, conferir com horrios e disponibilidades de vagas nos hotis, etc. Se essas
empresas disponibilizarem Web Services, a agncia de turismo pode automatizar esse
processo enviando requisies SOAP para cada Web Service e montando o pacote final, com
base nas informaes fornecidas pelo cliente.
Uma aplicao Web Service Consumer no precisa necessariamente ser um browser. Uma
aplicao desse tipo pode ser escrita em praticamente qualquer linguagem, utilizando interface
dedicada ao invs de um browser.
CSDL
5eb Ser)ices Description Lan/%a/e - a WSDL descreve os mtodos de um 5eb Ser)ice.
Clientes que queiram utilizar os servios de um 5eb Ser)ice devem conhecer sua interface,
atravs da WSDL. A WSDL semelhante a uma $ype Library, a diferena que est em
formato XML.
Cr%ando u+ Ceb Ser)%(e
Clique em File;*e2;,therC5ebSer)ices>S,A( Ser)er Application.


Figura. Criando um 7ebService
Na caixa que aparece escolha a opo 5eb App Deb%//er e-ec%table. Em Class *ame digite
"Soma.


Figura. Definindo o tipo de servidor
O Delphi perguntar se voc quer criar uma interface para o mdulo SOAP. Responda Des.


Figura. Criando uma interface
Preencha as opes como mostra a figura a seguir.


Figura. Op.es da interface do servio
Aperte OK. Clique em File;Sa)e All. Salve a %nit".pas como "uFrmMain.pas, a %nit'.pas como
"uWM.pas, deixe o nome sugerido para SomaIntf.pas e SomaImpl.pas e salve o projeto como
"SomaService.dpr. Selecione o formulrio e d a ele o nome de "FrmMain. Selecione o
5ebMod%le e d a ele o nome de "WM.


Figura. 7ebModule da aplica!o


Abra a unit SomaIntf. Declare o mtodo Somar como mostrado a seguir.

unit !omaInt5/

interface

uses Invoe:egistry@ &y0es@ L!B)iltIns/

type

I!oma = interface+IInvoable.
[2F7S$DNSD'OZNDDODBA$OZNARO$7BDSD;7<D'EG2]
function !omar+N)m(: !ingle/ N)mA: !ingle.: single/ stdcall/
end/

i/ple/entation

initiali@ation
Inv:egistry.:egisterInter5ace+&y0eIn5o+I!oma../

end.

Como voc pode ver, nossa interface ISoma descende da interface IIn)o0able. Repare tambm
que nessa unit apenas definimos a interface. A implementao feita em uma unit parte.
IIn)o=ab#e - de>%n%ndo
Assim como I1n0no2n a interface base para todas as interfaces COM, IIn)o0able a
interface base para todas as interfaces que definem 5eb Ser)ices. Veja sua declarao:

FC1HG
IInvoable = interface+IInter5ace.
end/
FC1OG

Como voc pode ver, sua declarao bastante simples. Na verdade, essa interface apenas
herda de IInterface e ativa o recurso de RTTI (diretiva $M). Nesse caso RTTI se faz necessrio
para que as chamadas de mtodos contidas em um pacote SOAP possam ser decodificadas e
repassadas ao mtodo apropriado da interface IIn)o0able. Ou seja, o servidor deve ser capaz
de chamar um mtodo e passar parmetros apenas lendo os dados em string contidos no
pacote SOAP.
TIn)o=ab#eC#ass - %+p#e+entando
$In)o0ableClass a classe base para todas as classes que implementam interfaces IIn)o0able.
Esta classe semelhante a classe $Interfaced,bect usada em aplicaes COM.
Abra a unit SomaImpl e implemente o Web Service dessa forma:

unit !omaIm0l/

interface

uses Invoe:egistry@ &y0es@ L!B)iltIns@ !omaInt5/

type

&!oma = class+&Invoable*lass@ I!oma.
public
function !omar+N)m(: !ingle/ N)mA: !ingle.: single/ stdcall/
end/

i/ple/entation

F &!oma G

function &!oma.!omar+N)m(@ N)mA: !ingle.: single/
begin
res)lt:=N)m(HN)mA/
end/

initiali@ation
Inv:egistry.:egisterInvoable*lass+&!oma./

end.

Execute a aplicao. Na prxima parte, veremos como criar uma aplicao para consumir este
WebService.
Parte <<,I SOAP e CebSer)%(es Ap#%(a7es (#%entes
Nesta parte do curso, veremos como criar uma aplicao que far acesso ao Web Service
criado na parte anterior.
At%)ando o Ser)%dor
Normalmente voc vai hospedar seu Web Service em um servidor IIS ou Apache. Em nosso
caso, estamos usando um servidor especial de depurao, feito pela Borland, o Web App
Debugger. Esse utilitrio dispensa o uso de um servidor Web comercial, porm deve ser usado
somente para testes e depurao.
Para ativ-lo clique no menu $ools;5eb App Deb%//er. No console do servidor clique no boto
Start.


Figura. 7eb 2pp Debugger
Clique no link que aparece no console. No navegador escolha nossa aplicao na lista e aperte
!o.


Figura. Descri!o do servio
Clique no link 5SDL ao lado de ISoma.


Figura. 7SD1 da interface
Copie a URL que aparece na barra de endereos do navegador.
Deixe o 5eb App Deb%//er rodando. Agora vamos fazer a aplicao cliente.
C#%ente Ceb Ser)%(e B Ceb Ser)%(e Consu+er
Clique em File|New A##lication$ Sal#e a unit com o nome de +uClienteSO"P.pas, e o pro-eto com
o nome de +ClienteSO"P.dpr,. D. o nome de +'rm(ain, ao )ormul/rio e Ca#tion +0e1 Ser#ices 2
SO"P,. Coloque um 1oto no )ormul/rio3 com o Ca#tion +Somar,3 e tr.s %dit. 4e-a a )i$ura%


Figura. 2plica!o cliente para servidor SO28
O o1-eti#o a$ora * clicar no 1oto e c5amar a )uno Somar do 0e1 Ser#ice3 tra)e$ando os dados
em 6(L78TTP at* o ser#idor.
I+portando a CSDL
Clique em File;*e2;,ther;5eb Ser)ices;5SDL Importer.


Figura. Importando a 7SD1 do servidor SO28
No 5SDL Import 5i@ard cole a URL que voc copiou anteriormente.


Figura. 7SD1 Import 7i9ard
Clique em *e-t e depois Finish. Salve a unit criada. Observe que o Delphi cria uma interface
IIn)o0able na aplicao cliente baseado nas informaes da 5SDL. Essa interface
exatamente a mesma que foi definida quando criamos o servidor SOAP.


Figura. Interface gerada a partir do documento 7SD1
Volte ao formulrio principal. Aperte Alt+F11 e escolha a unit ISoma" na lista. Coloque no
formulrio um componente HTTPRIO (primeiro componente da paleta 5ebSer)ices).


Figura. :""8RIO $ Remote Invo;able Ob-ect
Defina sua propriedade 5SDLLocation, Ser)ice e (ort.


Figura. Configurando o :""8RIO
No evento ,nClic0 do boto digite:

0roced)re &'rm1ain.B)tton(*lic+!ender: &,b-ect./
var
,b- : I!oma/
n(@nA@n$ : single/
begin
,b-:=+P&&P:I,( as I!oma./ KK ,b-:=*o!oma.*reate/
n(:=!tr&oInt+7dit(.&e3t./
nA:=!tr&oInt+7ditA.&e3t./
n$:=,b-.!omar+n(@nA./
7dit$.te3t:='loat&o!tr+n$./
end/

Observe que a nica diferena do cdigo do cliente SOAP para o cliente COM o modo como o
objeto criado.


Figura. Soma feita no servidor SO28
Quando o usurio aperta o boto Somar, os nmeros "3 e "4 so codificados em um pacote
SOAP/XML e enviados ao Web Service. O Web Service recebe o nome do mtodo a ser
chamado (Somar) e usando RTTI invoca o mtodo de interface apropriado, por meio dos
componentes E$$(SoapDispatcher e E$$(Soap(ascalIn)o0er.

Parte <<,II DataSnap e SOAP
Continuando o nosso curso, veremos neste artigo como criar uma soluo simples
multicamadas usando DataSnap e SOAP. Clique em File;*e2;,therC5ebSer)ices>S,A(
Ser)er Application. Na caixa de dilogo que aparece d o nome de "AppServerSOAP para o
servidor 5eb App Deb%//er.


Figura. Criando um servidor SO28 < DataSnap
Responda *o quando o Delphi perguntar se voc quer criar uma interface.
Salve a %nit".pas como "uFrmMain.pas, a %nit'.pas como "uWM.pas e o projeto como
"AppServerSOAP.dpr. Selecione o formulrio e d a ele o nome de "FrmMain. Selecione o
5ebMod%le e d a ele o nome de "WM.
Clique em File;*e2;,therC5ebSer)ices>S,A( Ser)er Data Mod%le. Na janela que aparece
digite "RDM para a opo Mod%le *ame.


Figura. Criando um SO28DataModule
Salve a unit criada como "uRDM. Configure o DataMod%le usando os mesmos componentes do
exemplo anterior.


Figura. SO28DataModule
Observe que a interface I4DM descende de IAppSer)erS,A(. A classe $4DM descende de
$SoapDataMod%le e implementa I4DM. IAppSer)erS,A( e IAppSer)er.

I:D1 = interface+I<00!erver!,<P.
[2FRD';N7B*OSDSBOD<R(OBR7<OASRR*DEDS7'EG2]
end/

&:D1 = class+&!oa0Data1od)le@ I:D1@ I<00!erver!,<P@ I<00!erver.
!"#*onnection: &!"#*onnection/
!"#Data!et: &!"#Data!et/
Data!etProvider: &Data!etProvider/
private
public
end/

Execute a aplicao. Ati)e o 5eb App Deb%//er. Faremos agora a parte cliente da aplicao.
SOAP Conne(t%on
Abra a aplicao DataSnap Client criada anteriormente. Coloque no DM um componente
SoapConnection da paleta 5ebSer)ices.

Figura. =sando SO28Connection
Configure sua propriedade 14L para:

htt0:KKlocalhost:E;E(K<00!erver!,<P.<00!erver!,<PKsoa0

Configure Connected para $r%e.
Conne(t%onBro=er
Coloque no DM um componente ConnectionBro0er da paleta DataSnap.


Figura. Connection3ro;er abstrai a cone)!o DataSnap
Esse componente abstrai para o ClientDataSet o tipo de conexo que ser utilizada. Por
exemplo, voc pode trocar sua conexo de DCOM para SOAP ou ainda COM+ sem precisar
alterar os ClientDataSets.
Figura. DataModule cliente
Aponte a propriedade Connection desse componente para S,A(Connection. Aponte a
propriedade 4emoteSer)er do ClientDataSet para ConnectionBro0er".
Testando o (#%ente DataSnap B SOAP
Execute a aplicao.


Figura. "estando a aplica!o DataSnap client com o servidor SO28
Parte <<,III /u#t%(a+adas no De#p*% DEEFBDEEG (o+ 8NET
Re+ot%n-
Muitas tecnologias existem atualmente, destinadas a proverem a comunicao entre
aplicaes. Essas aplicaes podem ser dois processos rodando na mesma mquina, ou em
duas mquinas de uma rede. Exemplos de tecnologias distribudas so: COM/DCOM/COM+,
RMI, CORBA, SOAP, RPC etc.
No .NET, a tecnologia responsvel pela construo de aplicaes distribudas se chama .NET
Remoting. Essa tecnologia substitui o antigo DCOM/COM+ (apesar de ainda poderem ser
usados no .NET) e oferece mecanismos que permite a comunicao entre clientes e servidores.
Observe que a arquitetura de objetos distribudos semelhante arquitetura de aplicaes de
BD cliente / servidor. A diferena crucial que o cliente estar usando obetos armazenados no
servidor, e no tabelas como em um sistema cliente/server. Ao invs de passarmos instrues
SQL, fazemos chamadas para mFtodos remotos.
Ar.u%tetura do 8NET Re+ot%n-
A 5%-ura H mostra a arquitetura do .NET Remoting. Temos uma aplicao servidora e uma
aplicao cliente, que se comunicam atravs de um Channel (discutido a seguir). O objeto
remoto independe de localizao.


Figura. .N/" Remoting> C#annel? Formatters? 8ro)ies e modos de ativa!o
Ob?etos Re+otos& /ars*a#-bI-Re>eren(e e /ars*a#-bI-,a#ue
No .NET, existem dois tipos de objetos usados em aplicaes distribudas:
Marshal<By<4eference - so passados por referncia, so criados remotamente no servidor e
so ento controlados remotamente pela aplicao cliente. A aplicao cliente faz uso de um
pro-y, que se encarrega de repassar as chamadas para o servidor remoto;
Marshal<by<3al%e - so objetos passados por valor e precisam ser serializados para o
transporte via rede. devem implementar a interface ISeriali@able ou receber o atributo
Seriali@able.
U+ exe+p#o pr@t%(o
Neste captulo criaremos um exemplo bastante prtico e original: um Chat que usar o
conceito de objetos distribudos e .NET Remoting para trocar mensagens entre usurios da
rede. Nossa aplicao ser composta de trs partes:
Ser)er < aplicao servidora que conter o objeto remoto que controla o chat;
Client G aplicao Windows Forms que permitir enviar e receber mensagens;
Intf G pacote que define classes e interfaces destinadas a comunicao entre cliente e servidor
(o "contrato). Esse "contrato usado por ambas as aplicaes, portanto vamos comear
fazendo a definio da interface.
Inter>a(es& (ontrato entre ser)%dor e (#%ente
Um dos fundamentos de qualquer sistema de comunicao de objetos distribudos o uso de
uma interface. Uma interface semelhante a uma classe, mas que possui somente mtodos
abstratos, ou seja, sem implementao. Esses mtodos devem ser implementados por uma
classe. Dessa forma, um objeto pode se comunicar com o outro apenas conhecendo a sua
interface, que funciona como uma espcie de contrato (5%-ura).


Figura. =ma interface um @contratoA entre cliente e servidor
Uma interface como se fosse um controle remoto. Voc consegue interagir com um objeto
remoto conhecendo o que ele oferece, tendo a interface que descreve cada funo, porm,
sem a mnima idia de como ele implementa essa funcionalidade internamente.
Cr%ando a %nter>a(e
No Delphi 2005, clique em FileC*e2C,therCDelphi for .*E$ (roectsC(ac0a/e. Salve o com o
nome de (ac0Intf.dp0 em um diretrio chamado Intf. A seguir, adicione uma unit ao pacote
(FileC*e2C,therC Delphi for .*E$ (roectsC*e2 FilesC1nit) e salve-a com o nome de
ChatIntf.
Altere o cdigo da unit como mostrado a seguir:

unit *hatInt5/

interface

type
[!eriali?able]
*hat1sg = class
Nome: !ystem.!tring/
1sg: !ystem.!tring/
DataPora: !ystem.Date&ime/
end/
*hat1sgs = array of *hat1sg/

I*hat = interface
procedure 7nvia1ensagem+1sg: *hat1sg./
function :e5resh: *hat1sgs/
end/

i/ple/entation

end.

Observe que definimos uma classe chamada ChatMs/, que representa uma mensagem do
chat. Ela possui os atributos *ome. Ms/ e DataEora. que representam o nome do usurio que
postou a mensagem (*ome), a mensagem em si (ms/) e a data/hora em que foi postada.
Como essa mensagem no ser controlada remotamente (ela deve ser completamente
serializada e enviada pela rede), a marcamos com o atributo Seriali@able. Tambm definimos
um array de mensagens, chamado ChatMs/s.
A seguir, criamos uma interface chamada IChat. Essa interface define o "protoloco de
comunicao entre cliente e servidor, ou seja, uma espcide de "contrato. O cliente deve
conhecer seus mtodos para poder interagir com o servidor. O mtodo En)iaMensa/em recebe
um Ms/, que a mensagem propriamente dita que ir trafegar pela rede. 4efresh retorna
todas as mensagens enviadas ao chat (um array de ChatMs/).
Pronto, basta compilaro Assembly clicando em (roectCB%ild. Isso ir gerar uma DLL.
Cr%ando o ser)%dor re+oto
Nosso servidor consistir de uma aplicao Windows Forms, que ter o formulrio somente
para fins de ativao e para manter a aplicao em execuo. Inicie ento uma nova aplicao
Windows Forms, dando o nome de Ser)er.dpr ao projeto.

D%(a: use um grupo ((roect !ro%p) para gerenciar facilmente os trs projetos desta
aplicao. Para isso, clique de direita sobre o (roect!ro%p" que est no (roect Mana/er e crie
ou adicione os projetos que desejar.


Figura. 8ro-ect group facilita o acesso ao pacote? cliente e servidor
Conforme comentei anteriormente, a interface usada por ambos os projetos, cliente e
servidor. O servidor implementa o chat, enquanto o cliente utiliza seus servios. Ento,
precisamos adicionar uma referncia no projeto servidor para o Assembly criado
anteriormente.
Para isso, clique de direita no nome do projeto no (roect Mana/er e escolha Add 4eference.
Na janela que aparece, vemos na lista superior apenas os Assemblies registrados no GAC.
Como nosso assembly privado, clique no boto Bro2se e localiza o (ac0Intf.dll, selecione-a
na lista e clique em OK.
Adicione uma nova unit ao projeto (FileC*e2C,therC Delphi for .*E$ (roectsC*e2
FilesC1nit), salve-a com o nome de %ChatSer)er.pas e digite o seguinte:

unit )*hat!erver/

interface

uses
*hatInt5/

type
*hat!erver = class +1arshalBy:e5,b-ect@I*hat.
1sgs: *hat1sgs/
0roced)re 7nvia1ensagem+1sg: *hat1sg./
5)nction :e5resh: *hat1sgs/
end/

i/ple/entation

function *hat!erver.:e5resh: *hat1sgs/
begin
res)lt := 1sgs/
end/

procedure *hat!erver.7nvia1ensagem+1sg: *hat1sg./
var
i: integer/
begin
i := #ength+1sgs. H (/
msg.DataPora := !ystem.Date&ime.Now/
!et#ength+1sgs@i./
1sgs[i O (] := 1sg/
end/

A clusula %ses faz referncia unit ChatIntf.pas, contida no assembly (ac0Intf.dll. A seguir,
temos a declarao da classe ChatSer)er:

*hat!erver = class +1arshalBy:e5,b-ect@I*hat.

Aqui estamos dizendo que a classe descende de MarshalBy4ef,bect, indicando que se trata de
um objeto que ser controlado remotamente e que implementa os mtodos da interface IChat.
O mtodo En)iaMensa/em simplesmente guarda a mensagem em um array (Ms/s) que
permanece ativo durante toda a vida til do objeto remoto. 4eresh simplesmente devolve ao
cliente todas as mensagens postadas.
Volte ao formulrio principal e no seu evento Load digite o seguinte:

uses )*hat!erver/
...
cnl := Ptt0*hannel.*reate+EEEE./
*hannel!ervices.:egister*hannel+cnl./
:emoting*on5ig)ration.:egister>ellMnown!ervice&y0e+
ty0e,5+*hat!erver.@2*hat!erver2@>ellMnown,b-ect1ode.!ingleton./

Declare a varivel cnl na seo public do formulrio:

cnl: Ptt0*hannel/

Declare os seguintes namespaces na clusula %ses da sesso interface:

!ystem.:)ntime.:emoting@
!ystem.:)ntime.:emoting.*hannels@
!ystem.:)ntime.:emoting.*hannels.Ptt0/

Vamos conhecer um pouco mais sobre o que significam os objetos e mtodos usados no cdigo
anterior.
C*anne#s e 5or+atters
O namespace System.4%ntime.4emotin/.Channels contm classes para suporte a channels
(canais), que so usados como meio de transporte para chamadas de mtodos de um cliente
para um objeto remoto. Channels so objetos que transportam mensagens entre aplicaes
remotas e so responsveis por "escutar mensagens remotas.
Antes de processar essas mensagens, um Channel pode enviar a mensagem para uma cadeia
de objetos Channel Sin0 (receptores). Cada Sin0 na cadeia recebe a mensagem, efetua
operaes especficas e repassa para o prximo Sin0.
Existem dois tipos de Channels no .NET:
EttpChannel < namespace System.4%ntime.4emotin/.Channels.Ettp;
$cpChannel < namespace System.4%ntime.4emotin/.Channels.$cp.
Formatters (formatadores) so responsveis por codificar/decodificar mensagens para
transmisso atravs de um Channel. Existem dois tipos de Formatters no .NET:
SoapFormatter;
BinaryFormatter.
O interessante que podemos ter uma mesma aplicao usando canais diferentes com tipos
de formatadores diferentes. Por exemplo, um objeto remoto por ser ativado tanto por
$cpHBinary, o que mais rpido em uma rede interna, quanto por EttpHSoap atravs da
internet.
Em nosso exemplo, declaramos uma varivel do tipo EttpChannel. O construtor da classe
recebe como parmetro o nmero da porta a ser utilizada, nesse caso usamos 8888.
C*anne#Ser)%(es
ChannelSer)ices, do namespace System.4%ntime.4emotin/.Channels. uma classe composta
inteiramente de membros estticos, de forma que no precisamos instanci-la para usar seus
mtodos. Oferece mtodos para manipular objetos Channels, como registrar, desregistrar,
obter uma lista de Channels registrados e assim por diante.
Em nosso exemplo, usamos o mtodo 4e/isterChannel de ChannelSer)ices para regitrar o
objeto cnl do tipo EttpChannel, criado na linha anterior.
T%pos de at%)a!o de ob?etos
Objetos remotos do tipo Marshal<By<4eference podem ser criados (instanciados) de duas
formas:
Servidor (Ser)er Acti)ation) - so registrados no .NET Remoting e so criadas no
servidor somente quando necessrio. No so criados quando o objeto pro-y criado
na mquina cliente, mas somente quando feita a primeira chamada de mtodo.
Objetos servidores podem ser ativados de duas formas:
o Sin/leton < somente um objeto reside na memria do servidor e todas
as chamadas clientes a esse objeto so serializadas;
o Sin/leCall G um novo objeto criado para cada solicitao cliente;
Cliente (Client Acti)ation) - a criao de objetos no servidor comandada pela
aplicao cliente.
Re+ot%n-Con>%-urat%on
4emotin/Confi/%ration, do namespace System.4%ntime.4emotin/, uma importante classe
destinada a manuteno e configurao de uma aplicao distribuda usando .NET Remoting.
Possui somente mtodos estticos.
Em nosso exemplo, chamamos o mtodo 4e/ister5ell6no2nSer)ice$ype, que registra em uma
aplicao servidora um determinado tipo como sendo remoto, tornando-o assim, acessvel por
outras aplicaes.
Na prxima parte deste artigo, veremos como criar a aplicao cliente.
Parte <<I< C#%entes para ap#%(a7es 8NET Re+ot%n-
Neste artigo veremos como criar a aplicao cliente para o servidor criado na parte anterior
deste curso.
Cr%ando a ap#%(a!o (#%ente
Inicie uma nova aplicao Windows Forms e salve todos os arquivos do projeto em uma pasta
chamada Client, dando o nome de Client.dpr ao projeto. Coloque no formulrio principal trs
$e-tBo-es. trs Labels. dois B%ttons e um ListBo-, ajustando-os conforme mostrado na 5%-ura
a seguir8


Figura. C#at> tela principal da aplica!o cliente
Precisamos adicionar uma referncia no projeto servidor para o Assembly que defina o
"contrato de comunicao entre servidor e cliente. Clique de direita no nome do projeto no
(roect Mana/er e escolha Add 4eference. Na janela que aparece, vemos na lista superior
apenas os Assemblies registrados no GAC. Clique no boto Bro2se e localiza o (ac0Intf.dll,
selecione-a na lista e clique em OK.
Declare os seguintes namespaces na clusula %ses da sesso interface:

!ystem.:)ntime.:emoting@
!ystem.:)ntime.:emoting.*hannels@
!ystem.:)ntime.:emoting.*hannels.Ptt0@
*hatInt5/

Declare os seguintes objetos na sesso p%blic do formulrio:

cnl: Ptt0*hannel/
*hat!erver: I*hat!erver/

No evento Clic0 do boto Conectar digite o seguinte:

cnl := Ptt0*hannel.*reate/
*hannel!ervices.:egister*hannel+cnl./
*hat!erver := <ctivator.=et,b-ect+ty0e,5+I*hat.@
!ystem.!tring.'ormat+2htt0:KKF;GK*hat!erver2@&e3tBo3(.&e3t.. as I*hat/

No evento Clic0 do boto En)iar digite o seguinte:

var
msg: *hat1sg/
begin
if *hat!erver = nil then e3it/
msg := *hat1sg.*reate/
msg.Nome := &e3tBo3A.&e3t/
msg.1sg := &e3tBo3$.&e3t/
*hat!erver.7nvia1ensagem+1sg./

Coloque um $imer no formulrio, altere seu Enabled para $r%e. Inter)al para "1000 (1
segundo) e no seu evento $ic0 digite:

var
1sgs: *hat1sgs/
1sg: *hat1sg/
begin
if *hat!erver = nil then e3it/
#istBo3(.Items.*lear/
1sgs := *hat!erver.:e5resh/
for 1sg in 1sgs do
#istBo3(.Items.Insert+;@
!ystem.!tring.'ormat+
2F;G[F(G] FAG2@[1sg.DataPora.&o!tring+2t2.@1sg.Nome@1sg.1sg]../
Testando o C*at
Para testar o chat, executamos primeiro a aplicao servidora e a mantemos ativa. A seguir,
basta executar n instncias da aplicao cliente, indiciando no primero $e-tBo- o nome e porta
do servidor remoto. Digite seu nic0, clique no boto Conectar e envie mensagens. A 5%-ura a
seguir mostra o chat em execuo.


Figura. =m c#at usando ob-etos distribu&dos e .N/" Remoting
Nota: para facilitar o exemplo e focar o exerccio no .NET Remoting, no implementamos
algumas funcionalidades bsicas como rolagem das mensagens, de forma que a ordem fica de
cima para baixo, conforme recebido. Alm disso, o mtodo 4efresh retorna todas as
mensagens a cada n segundos. Uma sugesto implementar o mtodo para retornar somente
as mensagens novas.

Parte <<< 8NET Re+ot%n- (o+ ban(o de dados
A ltima parte deste curso mostrar como criar aplicaes multicamadas no Delphi 2005 /
2006 que faro acesso a banco de dados.
Ar.u%tetura de ap#%(a7es d%str%buJdas (o+ BDP e 8NET Re+ot%n-
A 5%-ura a seguir mostra a arquitetura de uma soluo usando as tecnologias do exemplo.
Nela, podemos identificar as seguinte camadas:
Banco de Dados - armazena os dados da aplicao, podendo ser qualquer SGDB
compatvel com ADO.NET ou BDP (Oracle, DB2, InterBase, Firebird, MySQL etc.);
Ser)idor de Aplica>Io - camada onde residem as regras de acesso, incluindo
DataAdapters para consultas e atualizaes, alm de mtodos especficos para
processamento de regras de negcio;
Cliente - faz acesso ao servidor de aplicao usando .NET Remoting. O acesso pode
ser feito via HTTP ou TCP. O tipo do cliente pode ser Windows Forms ou Web Forms.
No caso de ser ASP.NET Web Forms, teremos uma quarta camada na arquitetura, o
browser.


Figura. 2r,uitetura de uma aplica!o multicamadas
A 5%-ura a seguir mostra onde cada um dos novos componentes do BDP deve ser utilizado.



Figura. Componentes 3D8 para cria!o de aplica.es multicamadas
Cr%ando o ser)%dor
Crie uma aplicao do tipo 5indo2s Forms. A partir do Data E-plorer, arraste a conexo
Employee, para criar um BdpConnection previamente configurado. Arraste tambm a tabela
Employee para criar um BdpDataAdapter.
Colocamos um DataSync e na sua propriedade (ro)iders adicione um item, conforme
mostrado na 5%-ura a seguir.


Figura. 2dicionando os Data2dapters na propriedade 8roviders do DataS0nc
Coloque um 4emoteSer)er, configure seu Channel$ype ($cp ou Ettp), a porta, o DataSync
(apontando para o DataSync") e A%toStart para $r%e.
A partir da, os DataAdapters podem ser "enxergados por uma aplicao remota. Fazendo
uma analogia com o DataSnap, o DataSync nesse caso funciona como um DataSet(ro)ider,
que prov acesso remoto aos DataAdapters (que so semelhantes s Q%eries da VCL). A
5%-ura a seguir mostra o formulrio do servidor.


Figura. Servidor de aplica!o
Clique em 4%nC4%n 5itho%t Deb%//in/ e mantenha o servidor em execuo.
Cr%ando u+ (#%ente C%ndo"s 5or+s
Inicie uma aplicao do tipo Windows Forms e coloque no formulrio principal um
4emoteConnection para conectar ao servidor anterior. Configure as propriedades Channel$ype,
(ort. (ro)ider$ype de acordo com os valores configurados no servidor. Em URI 4emoteSer)er".
Veja a 5%-ura.


Figura. Configura!o do RemoteConnection

Coloque no formulrio um DataSet. Para "enxergar os DataAdapters do servidor referenciados
pelo DataSync, coloque um DataE%b e configure seu Data(ort para 4emoteConnection" e
aponte sua propriedade DataSet para DataSet". Ative o componente. Observe que o DataSet
ser preenchido nesse momento com as tabelas do servidor (propriedade $ables).
Coloque um Data!rid e configure seu DataSo%rce e DataMember. Coloque um B%tton e no seu
evento Clic0 digite:

procedure &>in'orm(.B)tton(_*lic+sender: !ystem.,b-ect/ e: !ystem.7vent<rgs./
begin
DataP)b(.<00ly*hanges/
end/

Veja a aplicao em execuo na 5%-ura a seguir8


Figura. Cliente 7indoBs Forms para o servidor de aplica!o
Cr%ando u+ (#%ente ASP8NET Ceb 5or+s
Vamos agora criar uma interface Web para nossa soluo multicamadas. Inicie uma nova
aplicao ASP.NET Web Forms e configure a conexo ao servidor. Os componentes utilizados e
as configuraes que devem ser feitas so exatamente as mesmas que da aplicao Windows
Forms, tanto que no repetirei aqui. Alm dos componentes de conexo, voc precisa de um
DB5ebDataSo%rce apontando para o DataSet. Usamos um DB5eb!rid e um DB5eb*a)i/ator,
configurando as propriedades DBDataSo%rce e $able*ame.
No evento ,nA%toApply4e9%ests e ,nApplyChan/e4e9%ests do DB5ebDataSo%rce digite:

DataP)b(.<00ly*hanges/

Veja na 5%-ura a seguir como ficou a aplicao.


Figura. Cliente 7eb Forms para o servidor de aplica!o
Passando parK+etros para (onsu#tas re+otas
muito simples passar um parmetro para um BdpDataAdapter que esteje parametrizado. Em
nosso exemplo, altere a propriedade SelectCommand.Command$e-t do BdpDataAdapter para:

!7#7*& 8 ':,1 71P#,J77 where 71P_N, = Y

Adicione o parmetro na propriedade (arameters do SelectCommand, dando o
(arameter*ame e So%rceCol%mn para Emp7*o. Em Bdp$ype escolha IntJ'. Rode a aplicao.
Na aplicao cliente Windows Forms, coloque um B%tton e um $e-tBo-. No evento Clic0 do
boto digite:

procedure &>in'orm(.B)tton(_*lic(+sender: !ystem.,b-ect/ e: !ystem.7vent<rgs./
var
da: Bd0Data<da0ter/
begin
da := DataP)b(.Providers[;].Data<da0ter as Bd0Data<da0ter/
da.!elect*ommand.Parameters[;].9al)e := &e3tBo3(.&e3t/
DataP)b(.:e5resh/
end/

No cdigo anterior, obtemos uma refer:ncia para o BdpDataAdapter remoto fazendo um
typecast no primeiro item da coleo (ro)iders. j que s temos um DataAdapter no servidor.
A seguir, passamos normalmente o valor para o parmetro, como se o Adapter fosse local. O
mtodo 4efresh do DataE%b atualiza a consulta (5%-ura).


Figura. 8assando par'metros remotamente
Do"n#oad
Voc pode fazer download de todos os exemplos deste curso a partir do endereo
http#HHcc.borland.comHA%thor.asp-KID&'''LLM. preciso fazer o cadastro na BDN, que
gratuito e pode ser feito a partir do endereo http://bdn.borland.com

dbExpress$ DataSnap e C#%entDataSet& T'(n%(as A)anadas
Para mais informaes sobre acesso a dados no Delphi e tcnicas avanadas, sugiro a leitura
do meu livro, "Delphi: Programao para Banco de Dados e Web, como apoio para o
aprendizado das tecnologias. Na obra mostro vrias tcnicas introdutrios e avanadas de
desenvolvimento com ClientDataSet, dbExpress e DataSnap (multicamadas, incluindo SOAP e
COM+). Para mais informaes, consulte o link http#HH222.cl%bedelphi.netH/%inther

Você também pode gostar