Você está na página 1de 9

DataSnap:Transfernciadeclassesgenri

cas
Vejanesteartigocomotransferirclassesgenricasentreaplicaes
Cliente/ServidorusandoDataSnapnoDelphi.

Introduo
medidaquevamosaprimorandoonossodesenvolvimento,utilizandoosprincpiosdedesenvolvimento
orientadoaobjetosetcnicasdepadresdeprojetos,praticamenteobrigatriooaprendizadodeconceitos
maisavanadosnalinguagememqueseestdesenvolvendo.
Esteposttomarcomobaseparaaexplanaoumasituaorealemuitocomumqueosdesenvolvedores
enfrentamnodiaadia.Temosquedesenvolverummtodonoservidorcapazdecadastrarositensdeum
carrinhodecompras.Situaobastantesimples,masquerequercertoconhecimento,tantonalinguagem,
comoemconceitosdeorientaoaobjetos.
Quandosepensanesteproblemaemquetemosquecriarumasoluo,sempreprocurandoutilizarasmelhores
prticasdedesenvolvimento,encontramosbasicamenteduaspossveissolues:
1)Criarummtodonoservidorquerecebercomoparmetroumaclasse,quenocasooproduto,equando
formosadicionarosprodutosdocarrinhotemosquefazerumlaoenviandoumaumosprodutosparao
servidorpersistir.
2)Criarummtodonoservidorquerecebercomoparmetroumalistadeprodutosaqualseradicionada
pelaaplicaoclienteparaqueoservidorseencarreguedepersistiressesprodutosnobancodedados.
Foramapresentadasduaspossveissoluesparaonossoproblema,masvemagrandepergunta:Qualdesses
doismtodosouarquiteturaseramelhorsoluoparaoproblemaemquesto?
Vamosanalisaraspossveissoluesparaidentificaramelhorparaaresoluodonossoproblema.
Aprimeiraumaboasoluodevidoasuasimplicidade,masseanalisarmaisprofundamenteperceberquea
suasimplicidadesimplesmentesuperficial.Naverdademuitadassoluesrpidasquetomamossoapenas
iluso,poismuitasdasvezessolhamosemcurtoprazo,masumsistema,principalmentecorporativo,dever
terumciclodevidagrandeeessasoluorpidapodercustarmuitonamanutenofuturadocdigo.Se
tivermosqueacrescentarumcontroledetransaonestapersistncia,perceberemosentoqueasoluo
simplessetornouumproblemamaiordoquetnhamosanteriormente.
Jasegundasoluo,elarequerumconhecimentomaiordodesenvolvedor,masemcompensaoteremos
maisfacilidadenamanutenodonossocdigo.Umgrandeexemplodessafacilidadeomesmousado
anteriormente,poisserealmentehouveranecessidadedeumcontroledetransao,ficarbemmaisfciltal
implementao.
Jquenonossoestudodecasoasoluomelhorfoiasegunda,entovamosfocarnelapraexplanaroobjetivo
dessepost.

ParaarmazenarosprodutosserutilizadaaclasseTList<T>daunitSystem.Generics.Collectionsparaquem
possuioDelphiXE2eXE3eparaasversesanterioresserutilizadaadaunitGenerics.Collections.
PrimeiramentevamosentenderoconceitodeGenerics,parasentotrabalharmosnatransfernciados
produtosparaoservidor.Algomuitoimportantequedevesersalientadonesteartigoqueelefoiescritopara
quedesenvolvedoresdenveisdiferentespossamtirarproveitodestecontedo,eporissoqueomesmo
sempreprocuraexemplificareexplicarcadaassuntoabordadonomesmo.
SegundooDelphiReference(materialutilizadocomoguiadeestudoparasetiraracertificaoDelphi
Developer),Genericssoconjuntosdeferramentasdeabstraoquepermitemadissociaodeumalgoritmo
(talcomoprocedureefunction)oudeumaestruturadedados(ComoumaClass,Record,Interface)apartirde
umoumaistiposparticularesqueaestruturadedadosoualgoritmoutiliza.Casotenhaacuriosidadede
aprendereentendermaisobreoconceitoeautilizaodosGenerics,recomendadoutilizaroDelphi
Reference,poispossuimuitosexemplosmencionadosl.EstaolinkparaoDelphiReferencefalandosobre
tiposGenericsoutypesGenerics,comoachar
melhor:http://docwiki.embarcadero.com/RADStudio/XE3/en/Generics_Index.
Observao:OfocodesseartigonofalarsobreGenericse,porisso,novamosabordartoprofundamente
esseassunto.
Depoisdestaabordagemconceitual,estamosaptosparainiciamosasprticas.

Prtica
VamosiniciarumnovoprojetoDataSnaputilizandooDelphiXE2,masquemtiverasversesdoDelphi2010em
dianteprovavelmentenoterqualquerproblemaparaacompanharesteartigo.
Vamosem:FileNewOther.

Figura1:IniciandoumnovoProjeto
VamoscriarumnovoprojetocomowizarddoDataSnapqueestnapastaDataSnapServer,clicarnaopo
DataSnapServeredepoisemOk.Serabertoowizardondevamospassarasinformaesbsicasde
funcionamentodoservidor.

Figura2:SelecionandooprojetoDataSnap
Observao:Noentraremosemdetalhessobrecadaopoquetemnowizard,poisessenoofocodesse
artigo.
NaprimeirapartedowizardvamosescolherVCLFormsApplications.Comomostraafigura3.

Figura3:Etapa1de4naconfiguraodoServidor
CliqueemNext.
Naprximaetapadeixeopadroenaetapa3/4,selecioneumaportaqualquer.Nesteartigofoiescolhidaa
porta8565.

Figura4:Etapa3de4naconfiguraodoServidor
CliqueemNext.Naetapa4/4deixecomoestecliqueemFinish.
Pronto.Jfoicriadoonossoprojeto.Foicriandopelowizardumform,umServerMethoddeexemploeum
ServerContainer.
Parafacilitarodesenvolvimentoforamrenomeadasasunitsdaseguinteforma:
Antigonome

NovoNome

Form1

UFViewPrincipal

ServerMethodsUnit

USMMetodos

ServerContainerUnit USCServidor

Tabela1:Nomesdasunidades
VamosadicionarumanovaunitenelacriaremosumaclassechamadaTProdutocomasseguintespropriedades
eosseguintestipos,comomostraaTabela2,esalvaremoscomonomeUProduto.
Propriedade Tipo
Nome

String

Valor

Double

Tabela2:InformaesdaclasseTProduto
AcasseTProduto,nonossoexemplo,svaipossuirdoisatributos,quenocasoNomeeValor.Claroqueno
projetorealessaclasseTProdutovaicontervriosatributos,podendoteratmtodos,masessenoofoco
desseartigo.
Agoravamoscriarumtipoouumaliasparaanossalistaeparaissovamosciarembaixodanossaclasse
TProdutootypeTItensProduto,comomostraaListagem1.
Listagem1:ImplementaodaunitTProduto
unitUProduto;
interface
usesSystem.Generics.Collections;
type
TProduto=class
private
prv_sNome:string;
prv_fValor:Double;
public
propertyNome:stringreadprv_sNomewriteprv_sNome;
propertyValor:Doublereadprv_fValorwriteprv_fValor;
end;
TItensProduto=TObjectList<TProduto>;
implementation

AgoravamosadicionarumnovoServerModuleemFile>New>Other,comomostraaFigura5.

Figura5:Etapaparaadicionarumnovoservermodule
SelecioneapastaDataSnapServeredepoiscliqueduasvezesemServerModule,comomostraaFigura6.

Figura6:AdicionandonoprojetoumnovoServerModule
VamosalterarapropriedadeNamedoServerModuleparaSMProdutoesalvaraUnitcomonomeUSMProduto.
Feitoisso,vamosporamonamassaparaoquerealmenteinteressa,queoenviodeclassesGenerics.
VamosprimeiramenteprogramaradeserializaonoservidornoServerModuleSMProduto.
VamosadicionarasunitsData.DBXJSON,Data.DBXJSONReflect,System.Generics.Collectionsparaquemtemo
DelphiapartirdaversoXE2eparaasdemaisversesadicioneasunitsDBXJSON,DBXJSONReflect,
Generics.CollectionsetambmsemesquecerdeadicionaraunitUProduto.
VamosadicionarummtodochamadopInserirItensVendacomaseguintedefinio,comomostraaListagem2.
Listagem2:DeclaraodomtodopInserirItensVenda
procedurepInserirItensVenda(pItensVenda:TJSONValue);

OParmetropItensVendaoobjetoserializado,entovamosfazeroprocessodedeserializaocomomostra
aListagem3.
Listagem3:ImplementaodomtodopInserirItensVenda
procedureTSMProduto.pInserirItensVenda(pItensVenda:TJSONValue);
varUnMarshal:TJSONUnMarshal;
oItensVenda:TItensVenda;
CTX:TRttiContext;
begin
CTX.GetType(TypeInfo(TItensVenda));
ifpItensVendaisTJSONNullthen//Verificandoseoobjetovindodoservidorigualanullounil.
Exit;

//InstanciandooTJSONUnMarshal,responsvelpordeserializaroobjeto
UnMarshal:=TJSONUnMarshal.Create;
try
//DeserializaoobjetoJSONefazumTypeCastparatrasnformarefetivamenteemTCliente
oItensVenda:=TItensVenda(UnMarshal.Unmarshal(pItensVenda));
finally
UnMarshal.Free;//LiberaoObjetodamemoria
end;
end;

VamosagoraadicionarumaaplicaoclienteselecionandooGrupoedepoiscomobotodireitoselecionando
AddNewProject(Figura7).SelecioneapastaDelphiProjectedepoiscliqueduasvezesemVCLForms
ApplicationcomomostraaFigura8.

Figura7:Adicionandoumprojetocliente

Figura8:AdicionandoumaaplicaoCliente
ComoprojetojcriadovamosrenomearaunitdoFormparaUFViewPrincipaleonomedoformpara
FViewPrincipal.
VamosAdicionarumTMemo,umTButtoneumTSQLConnectionaoformevamosrenomeloscomomostraa
Tabela3.
Nomedaclasse NovoNome
TMemo

MJSON

TButton

BInserirItensVenda

TSQLConnection

SQLCServidor

Tabela3:Nomesdoscompontensdoform
OrganizesuatelaparaquefiqueparecidocomaFigura9.

Figura9:Organizaodatela
VamosfazerasdevidasconfiguraesparaqueoSQLCServidorpossaseconectarcomaaplicaoservidora.
Observao:NoveremosdetalhessobrecadapropriedadedoTSQLConnection,poisessenoofocodo
artigo.
VamosconfiguraroTSQLConnectionsegundoaTabela4.
Propriedade NovoValor
Drive

Datasnap

Port

8565

Tabela4:ConfigurandoaspropriedadesdoTSQLConnection
CliquecomobotodireitonoSQLCServidoreemGenerateDataSnapclienteclasses,comomostraaFigura10.

Figura10:GerandoClasseProxy
Pronto.SergeradaumaclasseProxyresponsvelporseconectarcomoservidor.Renomeieaunitpara
UProxy.VamosagoraimplementarobotoBInserirItensVenda,comomostraaListagem4.
Listagem4:ImplementaodobotoBInserirItensVenda
procedureTFViewPrincipal.BInserirItensVendaClick(Sender:TObject);
varoItensVenda:TItensVenda;
oProduto:TProduto;
oProxy:TSMProdutoClient;

Marshal:TJSONMarshal;
oObjetoJSON:TJSONValue;
begin
oItensVenda:=TItensVenda.Create(True);//Informaparaalistaqueosobjetosqueestiveremnalistatambmseroliberadosjuntoscomalista
try
{$REGION'Passandoosprodutosparaalistadeobjetos'}
oProduto:=TProduto.Create;
oProduto.Nome:='Produto01';
oProduto.Valor:=25;
oItensVenda.Add(oProduto);
oProduto:=TProduto.Create;
oProduto.Nome:='Produto02';
oProduto.Valor:=27;
oItensVenda.Add(oProduto);
oProduto:=TProduto.Create;
oProduto.Nome:='Produto03';
oProduto.Valor:=2527;
oItensVenda.Add(oProduto);
{$ENDREGION}
ifAssigned(oItensVenda)then//Verificandoseoobjetofoicriado
begin
Marshal:=TJSONMarshal.Create;//Instanciandooobjetoresponsvelporserializar
try
oObjetoJSON:=Marshal.Marshal(oItensVenda);//SerializandodefatooobjetooItensVendaparaJSON
finally
Marshal.Free;//Liberandooserializador
end;
end
else
//CasooObjetooItensVendanotenhasidoinstnciadoserenviadoparaoservidorumobjetodotipoJSONNull
oObjetoJSON:=TJSONNull.Create;
SQLCServidor.Connected:=True;//Seconectandocomoservidor
//CriandooproxydoServerModuleTSMCliente
oProxy:=TSMProdutoClient.Create(SQLCServidor.DBXConnection);
MJSON.Text:=oObjetoJSON.ToString;//JogaoobjetoJSONnomemo
oProxy.pInserirItensVenda(oObjetoJSON);//Enviaositensdavendaproservidor
finally
oItensVenda.Free;
oProxy.Free;
oItensVenda.Free;
end;
end;

Agoraqueaaplicaoclientefoiimplementada,stestarmos.OresultadodoTMemoMJSONdeveser
parecidocomodafigura11.

Figura11:Testandoinserodeitens
Pronto.AgoraparaconcluironossoartigodeveserenfatizadaacriaodeumtypeTItensProduto,criadona
Listagem1.TodoobjetoGenericqueforserializadodevesecriarumaliasouumtypeparaele,poisoobjeto
TJSONMarshalconsegueserializar,masoobjetoTJSONUnMarshalnoconseguedeserializarsenoforcriado
umtypeouumaliasqueaponteparaadeclaraogeneric.Ouseja,todavezquefortrafegarumobjeto
GenericentreaplicaesutilizandoJSON,devesecriarumtypeparaapontarparaotipoGeneric,comomostra
aListagem5enodevesimplesmentedeclararavarivel,comomostraaListagem6,poisprovocarumerro
noservidor.
Listagem5:DeclaraodeumtypequereferenciaumtypeGeneric
Type

TItensVenda=TObjectList<TProduto>

Var

oItensVenda:TItensVenda

Listagem6:Declaraodeumavarivelsemacriaodeumtype
Var
oItensVenda:TObjectList<TProduto>

Concluso
Comofoivistonesseartigo,nocomplicadorealizaratrocadeclassesgenricasentreaplicaes
Cliente/Servidor.Comessesconceitosqueforamadquiridosnesseartigojpodemosterumabaseparao
desenvolvimentodeaplicaescorporativascomumgrauaindamaiordecomplexidade.bastantesimples
essatrocadeinformaesentreaplicaes.
importanteressaltarqueutilizandoestastcnicasdeserializaoemJSONosnossosservidoresjficam
aptosparaseremconsumidosporaplicaesfeitasemoutraslinguagens,comoC#,Java,PHPeetc.,desde
queasmesmassuportemJSON,quepraticamentetodassuportam.
Ficamosporaqui,efiquemlivresparaescreveremcomentrios,crticasesugestesparanovosartigos.Fiquem
comDeus.