News & Events
Tutorial: Criando meu app step-by-step – Reflection – Parte VII
- 11 de novembro de 2014
- Posted by: Adriano Santos
- Category: Notícias XE7 [Tutorial]
Reflection, novo conceito de desenvolvimento de servidores DataSnap com RAD Studio XE e FireDAC. Mencionei isso no post passado referente ao Tutorial: Criando meu app step-by-step – DataSnap – Parte VI quando disse que iríamos avançar um pouco mais em nosso tutorial. Pois bem, chegou a hora. Nessa sétima parte de nossa sequência, veremos como exportar um DataSnap do servidor para o cliente em formato FDJSONDataSet, nova classe no RAD Studio XE.
Também vimos a criação do nosso banco de dados Firebird 2.5 em nossa vídeo-aula complementar no YouTube nos preparando já para fazer o sincronismo entre servidor e cliente. Vejamos o que foi dito na versão anterior desse post.
- Criação do servidor DataSnap;
- Criação do módulo de conexão com o servidor DataSnap;
- Teste de conexão.
Nessa sétima parte, faremos a exportação da primeira tabela do banco no lado servidor, bem como seu uso no lado cliente. Veja:
- Criação da tabela do banco de dados no Firebird;
- Criação dos métodos de exportação de Títulos no lado servidor;
- Leitura e atualização da tabela Títulos local no dispositivo móvel;
Requisitos:
Criando a tabela no banco de dados Firebird
A primeira providência a ser tomada aqui é criar nossa primeira tabela no banco de dados Firebird. Sendo assim, faremos a abertura do banco no IBExpert. Não entrarei em detalhes quanto ao uso de outras ferramentas de acesso ao SGDB Firebird, pois está fora do escopo de nosso projeto.
#Dica: O IBExpert é uma excelente ferramenta de acesso ao Firebird e Interbase e possui uma versão Personal FREE, que possui recursos limitados, mas suficientes para a maioria das ações que precisamos fazer. Basta cadastrar-se no nesse link e então receber sua cópia FREE.
Com o IBExpert aberto e seu banco devidamente conectado, clique com o botão direito do mouse em Tables e em seguida em New Table. À direita e acima, você encontrará o campo para nomear nossa tabela. Ele estará com o valor NEW_TABLE. Modifique-o para TITULOS.
Crie a tabela do banco exatamente igual a que criamos para a versão SQLite, se preferir confira a Figura 1 que mostra a tabela criada no IBExpert. A única diferença está nos campos de imagem, FOTO e MINIATURA que são do tipo BLOB com Sub_Type = BINARY.
Figura 1. Tabela Títulos no Firebird
Reflection do FireDAC – Configuração do servidor DataSnap
Conforme podemos ver no título desse artigo, veremos um novo conceito de desenvolvimento de nosso servidor DataSnap: Reflection. Um classe foi recentemente adicionada ao Delphi para esse propósito presente na unit Data.FireDACJSONReflect. Nós podemos agora fazer a exportação de DataSets do servidor para o cliente de uma maneira mais simples e ao mesmo tempo mais inteligente. Por exemplo: se precisarmos enviar diversos DataSets do servidor para o cliente em uma única instrução, basta usarmos TFDJSONDataSets em um Function e podemos adicionar mais de um DataSet ao Result da função. Veremos isso mais delalhadamente, por enquanto vamos fazer a exportação apenas de um único DataSet, a tabela de pedidos.
Para isso faremos agora as configurações necessárias para acessar o servidor de banco de dados Firebird usando o componente FDConnection. Abra o servidor DataSnap criado no artigo anterior e encontrei nosso ServerMethod que tem o nome UntServerMetodos. É nele que colocaremos nossas tabelas e conexões com o Firebird.
É claro que o mais certo seria isolarmos os nossos Queries de demais componentes de acesso, como o FDConnection, mas para nosso exemplo, não precisaremos dessa abordagem. Apenas insira um FDConnection no ServerMethod e dê o nome de FDConexao a ele. Em seguida clique duas vezes no componente para configurarmos suas propriedades de acesso.
Na parte superior da janela, selecione o combo referente ao Driver ID e escolha FB. Feito isso, o Delphi modificará os parâmetros na parte de baixo para que sejamos capazes de configurar os dados de acesso. Em DataBase configure incluindo o endereço completo do arquivo de banco de dados, em nosso caso LOCADORASERVER.FDB. E seguida configure seu usuário e senha, SYSDBA e masterkey, respectivamente. Em Protolo, marque TCPIP. Clique em Test para verificar se está tudo ok com a conexão. No nosso caso, estamos usando o Firebird 2.5, conforme demonstrado em vídeo-aula. Observer a Figura 2 as configurações básicas.
Figura2. Conexões com o servidor DataSnap
Agora basta incluir no ServerMethod um componente do tipo FDQuery, para que possamos fazer uma Query na tabela TITULOS para exportarmos para o servidor. Dê o nome de qryTitulos a esse query e escreva a seguinte instrução SQL em sua propriedade de mesmo nome.
SELECT * FROM TITULOS
Bem simples, não? Exato, não queremos complicar nada nesse momento, apenas aprender a exportar o DataSet. Certo, agora vamos fazer a function de retorno dessa tabela. Pressione F12 para ver o código-fonte e procure a seção Public. Declare a nossa function como na linha a seguir:
function GetTitulos: TFDJSONDataSets;
Perceba que estamos usando a classe TFDJSONDataSets como retorno da função. Agora, precisamos pressionar CTRL + SHIFT + C para que o Delphi crie o escopo de nosso método. Escreveremos o código da Listagem 1.
function TSrvServerMetodos.GetTitulos: TFDJSONDataSets; begin //Devolve para o cliente o DataSet de Pedidos //Elimina cache qryTitulos.Active := False; Result := TFDJSONDataSets.Create; TFDJSONDataSetsWriter.ListAdd(Result, qryTitulos); end;
Listagem 1. Código de exportação do DataSet TITULOS
Moleza para entendermos. Primeiramente nós fechamos a Query qryTitulos para evitar enviarmos ao cliente algo que já esteja em cache. Em seguida nós criar uma instância de TFDJSONDataSets (nosso resultado) associando-o ao Result do método.
Por fim, usamos a classe TFDJSONDAtaSetsWriter para adicionar TODO o conteúdo da Query ao Result, ou seja, quantos forem as linhas listadas no qryTitulo serão adicionados ao Result e consequentemente recebidos pelo cliente. Eu disse “linhas listadas”, mas creio que não perceberam que não abrimos a query em momento algum certo? Pois bem, o método ListAdd já faz isso para nós, então não se preocupe.
Evidentemente que em uma situação real, precisaríamos, talvez, passar um parâmetro do cliente para o servidor informando um determinado filtro a Query, algo como: TRAGA OS TÍTULOS QUE NÃO ESTÃO ALUGADOS. Mas isso é assunto para mais tarde.
Compile o servidor e veja se tudo está correto.
#Dica: Provavelmente a classe TFDJSONDataSets não será encontrada, resultando em um “error compiler”. Portanto, adicione a unit Data.FireDACJSONReflect ao uses do nosso ServerMetodos.
#Dica: Não esqueça de clicar com o botão direito do mouse em nosso qryTitulos escolher Fields Editor e com a janelinha aberta, clicar com o direito novamente e então usar o Add all fields para que todos os campos da tabela sejam adicionados.
Execute o servidor DataSnap em modo SEM Debug clicando com o botão direito no Project Manager e em seguida em Run Without Debbuging (Figura 3)
Figura 3. Rodando o servidor em modo stand-alone
Preparando o cliente para acesso
Primeira coisa que quero fazer aqui é testar sua memória. Não, não quero que abra nenhum dos artigos sobre games da memória publicados aqui no site. Quero apenas que lembre-se. Fomos até o servidor DataSnap e MODIFICAMOS nosso servidor incluindo novos recursos, nesse caso um novo método. Então, qual o primeiro passo aqui para começar a enxergar esse novo recurso?
Se respondeu que devemos abrir a unit Modulo Cliente, clicar com o direito no DSRestConnection1 e em seguida em Generate DataSnap client classes (Figura 4), Bingo! Acertou na mosca.
Figura 4. Atualizando o cliente
Precisamos fazer isso para que nosso Proxy seja atualizado com o novo método, GetTitulos. Ao gerar novamente o proxy, ele será imediatamente aberto, bastando apenas salvar e fechar essa unit. Lembre-se, não precisamos alterar nada no Proxy.
Preparando o Sincronismo
Nessa última parte desse artigo, avançaremos pouco, pois desejo detalhar mais a tela de sincronismo na parte VIII, que ficará bastante grande. Faremos apenas o entendimento do que será feito acrescido de um pouco de código.
Retorne até a tela principal do sistema com o nome de frmMain. No capítulo anterior, nós deixamos um item de ListBox a mais para testarmos a conexão com o servidor. Quero apenas que apague o Label e o TEdit inserido e deixe o botão. No código do botão, quero que insira o código da Listagem 2.
procedure TfrmMain.spbSincronizarClick(Sender: TObject); var LDataSetList : TFDJSONDataSets; begin MessageDlg('Confirma sincronismo de dados?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0, procedure (const AResult: TModalResult) begin //Efetua o download da tabela TITULOS vinda do Servidor DataSnap LDataSetList := ModuloCliente.SrvServerMetodosClient.GetTitulos; //Prepara o MemoryTable temporário memTemporario.Active := False; //Fazemos um teste para verifica se realmente há DataSet no retorno da função Assert(TFDJSONDataSetsReader.GetListCount(LDataSetList) = 1); //Adicionamos o conteúdo do DataSet "baixado" ao Memory Table memTemporario.AppendData(TFDJSONDataSetsReader.GetListValue(LDataSetList, 0)); end ); end;
Listagem 2. Código prévio de sincronismo
Muito bom. A explicação não é longa, mas exige atenção. A primeiro coisa que fazemos aqui é declarar uma variável do tipo TFDJSONDataSets. Lembre-se de adicionar a unit referente a essa classe em nosso uses. Em seguida nós criamos uma MessageDlg, mas há um porém nisso tudo que terei que dar uma pausa para explicar antes.
Pausa para métodos anônimos
No RAD Studio XE7 houve uma pequena mudança no MessageDlg, agora ele precisa de um novo parâmetro para saber que é uma janela Modal e que precisa obedecer a um retorno *O sim. Nesse caso, repare que estamos usando um método anônimo, programação avançada do Delphi. Não entendeu? Vamos separar as coisas então:
Normalmente usamos um MessageDlg assim:
if MessageDlg('Confirma sincronismo de dados?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = mrYes then //fazemos algo end;
Somente isso já fazia com que a aplicação parasse e aguardasse o usuário pressionar em Yes ou No, mas agora é diferente. Precisamos fazer um “algo” mais. Após o último parâmetro, o HelpContext, passamos um método anônimo para a MessageDlg, ou seja, criamos um PROCEDURE no último parâmetro, veja:
MessageDlg('Confirma sincronismo de dados?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0, procedure (const AResult: TModalResult) begin //faz algo end ); end;
Dessa forma, quando o Yes for detectado, o código que será executado é o nosso procedure (const AResult: TModalResult) […]. Entraremos em mais detalhes em outros tutoriais. Apenas entenda a nova sintax.
Retomando o raciocínio
Em nosso método anônimo nós não temos muita codificação, repare. São apenas 4 (quatro) linhas, o resto são comentários. Pois bem, a primeira coisa que fazemos é receber na variável LDataSetList a lista de DataSets recebida do servidor com o uso do método GetTitulos. Nesse caso estamos recebendo apenas UM DataSet. Depois de fazer isso, nós fechamos o MemoryTable. Adicionei um FDMemoryTable na janela, pois receberemos o conteúdo da Query do Servidor e adicionaremos dentro do MemoryTable no cliente, assim podemos fazer qualquer coisa com ele depois.
A próxima linha é apenas um teste para nos certificarmos de que realmente a lista de DataSets possui ao menos um DataSet. Fazemos isso usando um Assert.
Por fim, usamos o método AppendData do MemoryTable para adicionar TODO o conteúdo do DataSet TITULO ao MemoryTable. O AppendData já deixa o MemoryTable aberto, ou seja, nesse momento precisamos apenas montar um LOOP para incluir esse dados em um banco de dados local. Bingo, nosso SQLite.
Na parte VIII de nosso Tutorial: Criando meu app step-by-step, faremos uso de ArrayDML para inserir rapidamente os dados no nosso SQLite.
Conclusões
Nessa sétima parte de nosso tutorial, avançamos para o uso de Reflection do FireDAC como uma forma mais eficaz e veloz de trazer informações do servidor DataSnap para o cliente. Criamos nossa tabela do Firebird e já estamos prontos para efetuarmos o sincronismo de dados.
O leitor Eduardo Belo fez um comentário pertinente a um ponto de nosso tutorial. Assim como mencionado no vídeo complementar desse post no YouTube, estamos utilizando a dll gds32.dll que refere-se ao Interbase, banco de dados da Embarcadero. Entretando, na realidade nesse post usei o modo de retrocompatibilidade no momento da instalação do Firebird 2.5. Isso faz com que o instalador renomeie a fdclient.dll para gds32.dll nos diretórios de sistema do Windows.
Vale lembrar que o Firebird, para conhecimento dos leigos, é derivado do Interbase, mas em um passado bastante remoto. Para quem não sabe, o Interbase até sua versão 6.0 era gratuito e de código-fonte aberto. Alguns desenvolvedores russos copiaram o fonte e criaram o Firebird, que aos poucos foi se distanciando em termos de funcionalidades em comparação ao Interbase. Hoje, são bastante diferentes.