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.