Persistindo dados com ClientDataSet
Aumente seu poder sobre a informação, persistindo dados desconectados do banco.
Salve Pessoal!!!
Antes de abordarmos o assunto desta semana, gostaria de fazer um agradecimento a todos que tem me enviado e-mails com dúvidas e sugestões, tenho aprendido muito com cada um. Continuem escrevendo, critiquem, mandem sugestões de matérias, tirem suas dúvidas e as minhas também; compartilhando para conquistar. ?
Mais um lembrete: não deixem de ir ao ClubeDelphi TechDay São Paulo, está imperdível. Três salas simultâneas, duas de palestras sobre Delphi e uma só de banco de dados. As palestras estão incríveis confira: http://www.clubedelphi.com.br/eventos/cdtd/indexsp.html
Não deixem de participar dos treinamentos do ClubeDelphi!
Persistindo Dados Localmente – A Motivação
Quando desenvolvemos aplicações em modelo Client/Server, temos questões do tipo como gerenciar a concorrência dos dados. Uma das soluções de maior sucesso hoje tem sido a utilização do DataSetProvider e do ClientDataSet para trabalharmos desconectados do banco e mesmo assim controlar e resolver as concorrências nos dados. Tudo isso devido à capacidade de persistirem em memória as alterações nos dados e identificar individualmente cada registro: o que está na base, o que foi lido e o alterado.
Por conseqüência desta capacidade e aliado a tecnologia e métodos específicos, podemos persistir toda esta estrutura de dados em memória localmente, através de arquivos binários, XML e XML-UTF8. São grandes os benefícios ao se fazer isto. Por exemplo: Uma de suas máquinas clientes perdeu a conexão com o banco e precisa salvar registros importantes que acabaram de ser trabalhados. Esta situação se resolve facilmente, basta salva-los localmente e criar uma rotina para “ouvir” a conexão e no restabelecimento da mesma, lê-se o arquivo de dados e envia a transação para o banco como se tivesse acabado de faze-la.
No caso de aplicações móbiles, este é um grande e poderoso recurso pois é fácil de utilizar, gera arquivos pequenos e mantém um histórico completo de alterações para cada registro e isto para não falar de transporte de informações entre sistemas, principalmente baseado no padrão XML.
Construindo o Exemplo
Em nosso exemplo vamos usar a seguinte estrutura no InterBase/FireBird:
CREATE TABLE PRODUTOS (
ID_PRODUTO INTEGER NOT NULL,
DESCRICAO VARCHAR(60) NOT NULL,
ESTOQUE INTEGER default 0 NOT NULL,
PRECOCOMPRA NUMERIC(15,2) NOT NULL);
CREATE GENERATOR GEN_PRODUTOS_ID;
ALTER TABLE PRODUTOS ADD CONSTRAINT UK_DESCRICAO_PRODUTOS UNIQUE (DESCRICAO);
ALTER TABLE PRODUTOS ADD CONSTRAINT PK_PRODUTOS PRIMARY KEY (ID_PRODUTO);
SET TERM ^ ;
CREATE TRIGGER TRG_GERA_ID_PRODUTO FOR PRODUTOS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
NEW.ID_PRODUTO = GEN_ID(GEN_PRODUTOS_ID,1);
END
^
SET TERM ; ^
Em seguida construiremos o seguinte formulário:
Faremos a conexão com DBExpress, adicione ao formulário um componente SqlConnection e configure a conexão com a base de dados onde foi criada a estrutura de dados, em seguida adicione um SqlDataSet, defina o SqlConection na propriedade referente, e no CommandText coloque o seguinte SQL:
Select * From Produtos
Where Descricao Like :Descricao
Certifique-se que o parâmetro Descricao possui o seu DataType como ftString (para averiguar isto, acesse a propriedade params do SqlDataSet).
Em seguida adicione um DataSetProvider, aponte a sua propriedade DataSet para o SqlDataSet. Adicione também ao formulário um ClientDataSet, aponte sua propriedade ProviderName para o DataSetProvider que acabamos de configurar, clique com o botão direito do mouse sobre o ClientDataSet, e acesse a opção Fetch Params, para que este pegue o parâmetro proveniente da consulta no SqlDataSet exportado pelo DataSetProvider. Adicione um DataSource, aponte sua propriedade DataSet para o ClientDataSet e aponte a propriedade DataSource do DBGrid para este DataSource que acabamos de configurar.
Vamos a programação dos botões:
Botão Consultar:
with CdsProdutos do
begin
.Close;
.Params[0].AsString := EdtDescricao.Text + '%';
.Open;
end;
Esta procedure efetua a consulta passando o parâmetro de consulta junto com o caracter coringa para o ClientDataSet. Botão Deletar:
if CdsProdutos.RecordCount > 0 then CdsProdutos.Delete;
Esta procedure verifica se existe registro para aplicar o método delete. Botão Aplicar:
if CdsProdutos.State in [dsInsert, dsEdit] then
. CdsProdutos.Post;
. CdsProdutos.ApplyUpdates(0);
. BtConsultarClick(Self);
Esta procedure testa o estado do DataSet para então aplicar as alterações no banco e executa novamente o procedimento de pesquisa.Botão Sair:
Application.Terminate;
Sem comentários.... Botão Salvar Dados Local:
if SaveDialog1.Execute then
begin
. CdsProdutos.SaveToFile(SaveDialog1.FileName,dfXML);
. ShowMessage('Dados Salvos Localmente');
end;
Este procedimento é que executa a chamada do método do ClientDataSet que faz a persistência local da transação em XML. Botão Carregar Dados Local:
if OpenDialog1.Execute then
begin
. CdsProdutos.LoadFromFile(OpenDialog1.FileName);
. ShowMessage('Dados Locais Carregados');
end;
Este procedimento carrega para o ClientDataSet os dados salvos no XML. Evento BeforePost do ClientDataSet:
if DataSet.State = dsinsert then
DataSet.FieldByName('ID_PRODUTO').AsInteger := 0;
Como o valor do campo chave é gerado somente no banco e este valor é requerido, simplesmente atribuímos a ele um valor qualquer na inclusão de dados. Eis abaixo como ficou a nossa aplicação:
Abaixo o arquivo XML gerado para persistir os dados:
Basta testar agora e explorar as funcionalidades. Um grande abraço e até semana que vem.