Motivação
Quando desenvolvemos aplicativos mobile, estes podem ter dois tipos de armazenamento: uma base de dados nativa, que fica localizada no próprio aparelho, ou então uma base localizada em um servidor de aplicação em um servidor externo. Nesse último caso, é necessário que o dispositivo esteja conectado à Internet para ter acesso às funções do software. Hoje em dia, uma outra alternativa bastante comum é manter duas bases de dados, ou seja, uma no aparelho e outra no servidor. Dessa forma, o usuário pode continuar trabalhando no aplicativo localmente e quando houver disponibilidade de conexão, seus dados locais podem ser transferidos para o servidor ou então os dados atualizados do servidor podem ser copiados para a base local.
Servidores DataSnap são um exemplo de tecnologia que pode ser utilizada para esse fim e, dentro desse contexto é importante conhecer as maneiras que permitem essa sincronização entre cliente e servidor. A execução chamada de Array DML é uma técnica que submete uma única instrução em SQL para a inserção de novos dados, utilizando um vetor de parâmetros que contém os novos registros. Essa técnica reduz a quantidade de comunicação entre o servidor e o cliente, o que garante uma melhor velocidade no tempo de execução dos comandos.
Saiba mais sobre: como criar aplicações DataSnap
Passo 1: Criando o método no servidor
Para este exemplo, devemos criar uma nova aplicação DataSnap e dentro da unit ServerMethodsUnit adicionar os componentes de acesso a dados para buscar os registros no banco. Para isso, serão necessários quatro componentes: FDConnection, FDQuery, FDPhysMSSQLDriverLink e FDStanStorageJSONLink. O primeiro é utilizado para realizar a conexão com a base, o segundo para executar a instrução SQL, o terceiro representa o driver de acesso ao SGBD (sistema gerenciador de banco de dados) e, por fim, o último diz respeito ao formato de dados que trafegará pela rede (neste caso, arquivos). A Figura 1 apresenta esses componentes.
Além disso, é também necessário um método remoto nesta mesma unit para que os dados sejam retornados para a aplicação cliente. Seu código pode ser visto na Listagem 1.
public function GetClientes(): TFDJSONDataSets; end; function TServerMethods1.GetClientes: TFDJSONDataSets; begin FDQuery1.Active := False; FDQuery1.SQL.Add('select idcliente, nome, genero, escolaridade from clientes'); Result := TFDJSONDataSets.Create; TFDJSONDataSetsWriter.ListAdd(Result, FDQuery1); end;
- Linhas 01, 02 e 03: Definição da função GetClientes() dentro da seção public da unit. O tipo de retorno do método é TFDJSONDataSets e na cláusula uses do arquivo o namespace Data.FireDACJSONReflect deve ser declarado;
- Linha 06: A query é fechada para a execução de um novo comando;
- Linha 07: Definimos o comando em SQL para buscar os dados tabela de clientes;
- Linha 08: Criamos o objeto que armazenará o resultado da consulta;
- Linha 09: Utilizando a classe TFDJSONDataSetsWriter, adicionamos à lista de retorno a variável Result, passando como parâmetro o componente FDQuery1, para que os dados relativos à consulta SQL sejam retornados.
Saiba mais sobre: como trafegar dados em formato JSON com DataSnap
Passo 2: Criando o método no cliente
A Figura 2 apresenta a interface gráfica da aplicação cliente, a qual é composta somente um um botão (TButton) e três componentes: FDConnection, que realiza a conexão com uma base de dados local; FDMemTable, que representa uma tabela em memória e que receberá os dados do servidor; e FDStanStorageJSONLink, para receber os dados no formato JSON. Em aplicações mobile, o componente de conexão pode estar ligado a uma base no SQLite, que é comumente utilizada para esse tipo de aplicativo. Quando o botão for clicado, os dados do servidor serão carregados na tabela em memória (FDMemTable1) e depois será feito o insert em massa para inserir todos os registros na base de dados local. O código da Listagem 2 apresenta esse processo, o qual é definido no evento OnClick do botão.
procedure TForm2.Button1Click(Sender: TObject); var dsClientes: TFDJsonDataSets; qryInsercao: TFDQuery; inserts: Integer; begin dsClientes := ClientModule1.ServerMethods1Client.GetClientes(); if TFDJSONDataSetsReader.GetListCount(dsClientes) = 1 then begin FDMemTable1.Active := false; FDMemTable1.AppendData(TFDJSONDataSetsReader.GetListValue(dsClientes, 0)); inserts := FDMemTable1.RecordCount; qryInsercao := TFDQuery.Create(Self); qryInsercao.Connection := FDConnection1; qryInsercao.SQL.Add('insert into clientes values (:id, :nome, :genero, :escolaridade)'); qryInsercao.Params.ArraySize := inserts; while not FDMemTable1.Eof do begin qryInsercao.ParamByName('id').AsInteger := FDMemTable1.FieldByName('idcliente').AsInteger; qryInsercao.ParamByName('nome').AsString := FDMemTable1.FieldByName('nome').AsString; qryInsercao.ParamByName('genero').AsString := FDMemTable1.FieldByName('genero').AsString; qryInsercao.ParamByName('escolaridade').AsInteger := FDMemTable1.FieldByName('escolaridade').AsInteger; FDMemTable1.Next; end; qryInsercao.Execute(inserts, 0); end; end;
- Linha 03: Declaramos a variável dataset do tipo TFDJSONDataSets, que armazena os registros carregados do servidor. É necessário informar na cláusula uses do formulário as units Data.FireDACJSONReflect e ClientModuleUnit1;
- Linha 04: Definimos a variável do tipo FDQuery para executar as inserções na base de dados local;
- Linha 05: Declaramos uma varíavel do tipo inteiro que armazenará a quantidade de registros que foram retornados do servidor;
- Linha 07: Invocamos o método GetClientes, declarado no servidor e acessado por meio da unit ClientModule1. A variável dsClientes receberá todos os registros provenientes da consulta SQL executada no servidor;
- Linha 08: Verificamos se algum dataset foi retornado do servidor, para posteriormente executar a cópia dos registros;
- Linhas 10, 11 e 12: Desativamos a tabela em memória, copiamos os dados do servidor para ela e então a variável inserts recebe a quantidade de registros retornados;
- Linhas 13, 14 e 15: Criamos a query em tempo de execução, a associamos ao componente de conexão e definimos o comando insert para inserir os dados, recebendo quatro parâmetros (id, nome, genero e escolaridade);
- Linha 16: A propriedade ArraySize da query recebe a quantidade de registros que serão inseridos por meio de Array DML;
- Linhas 17 a 24: Por meio de uma estrutura de repetição, percorremos a tabela em memória registro por registro e associamos os parâmetros da query de inserção aos respectivos valores da memory table;
- Linha 25: Por meio do comando execute, executamos todos os comandos de inserts.
Com isso, temos uma estrutura que primeiramente faz a leitura dos registros do servidor e posteriormente os insere em uma base de dados local. Conforme mecionado anteriormente, esse código pode ser utilizado para sincronizar aplicação cliente e servidora, mantendo-as atualizadas.
Curso relacionado: Multicamadas com Delphi e DataSnap