Nenhum comentário Download


Delphi – Parte V

 

Vimos no artigo anterior, o inicio dos exemplos sobre banco de dados. Nesse artigo veremos mais dicas sobre desenvolvimento de aplicações cliente/server com dbExpress no Delphi, onde a principal será a parametrização dos cadastros.

 

Imagine o nosso cadastro de clientes ter algo em torno de 500 registros, o que não é nada de tão absurdo. Pelo que construímos até agora, teríamos o DBNavigator para navegar entre os registros, o que não tem nenhuma facilidade.

 

Vamos alterar o projeto para que as consultas sejam parametrizadas e possamos modificar o cadastro. Teremos assim, performance da aplicação pois teremos em memória apenas os registros necessários para a edição dos dados.

Parametrizando as consultas

Para parametrizar as consultas precisamos modificar a consulta SQL adicionando o parâmetro que desejamos. Veja no código a seguir, como ficará a consulta para o cliente.

 

select nCdCliente, sNmCliente, tDtNascimento, nVlLimite

from CLIENTE

where nCdCliente = :nCdCliente

 

Assim, criamos um parâmetro para a consulta (basta ter dois pontos antes). Ao fechar o editor, a propriedade Params do SQLDataset mapeia os parâmetros adicionados no SQL (Figura 1).

 

 

Figura 1. Configurando o parâmetro do cadastro de cliente

 

Configure o parâmetro para o tipo correto, nesse exemplo, ftInteger. Precisamos “repassar” esse parâmetro para o ClientDataSet. Para isso, basta clicar com o botão direito no componente e escolher a opção Fetch Params. Pronto. Para conferir, acesse a propriedade Paras do cdsCliente, ela deve ter a mesma configuração do dsCliente.

 

Agora, se abrirmos a aplicação você notará que nenhum registro é mostrado. Obviamente, devido a mudança do SQL. Como podemos então mostrar os dados? Precisamos ter uma consulta auxiliar para buscarmos o registro que precisamos mudar.

 

Isso já introduz um conceito importante no nosso projeto, o de performance. Não precisamos retornar todos os registros do cadastro (imagine 5, 10 mil registros) para modificar um apenas. Vamos retornar para o cadastro, apenas o registro que desejamos alterar.

Modificando o cadastro de cliente

Precisamos mudar o layout do cadastro de clientes. Precisamos adicionar uma pesquisa para que possamos retornar o registro que o usuário vai alterar. Vamos criar abas para o cadastro, onde teremos uma para o cadastro em si e outra para um grid de pesquisa.

 

Adicione um PageControl no formulário e insira dois TabSheets. Crie uma aba com o texto: “Dados gerais” e outra como “Pesquisa”. Na aba Dados gerais adicione os controles de tela (podemos remover o DBNavigator). Veja na Figura 2 como ficou o cadastro.

 

 

Figura 2. Usando abas no cadastro de clientes

 

Veja que nosso cadastro ficou mais bonito. Agora, precisamos configura a aba de pesquisa. Adicione um Edit, um Grid e um DataSource. Faça a ligação do DataSource com o grid. Veja na Figura 3 a aba de pesquisa.

 

 

Figura 3. Aba de pesquisa no cadastro de cliente

 

Precisamos configurar uma consulta para ser usado na pesquisa do cadastro. Nesse tipo de pesquisa, não precisamos retornar uma quantidade grande de dados, precisamos apenas o código e um campo referente a descrição do cadastro (nesse caso, o nome do cliente).

 

Vamos criar outro Data Module para conter os componentes para as pesquisas que vamos usar na aplicação. Fica a seu critério para usar apenas um Data Module, apenas atente para colocar o novo Data Module a ser criado na inicialização do projeto.

Pesquisas auxiliares

Crie um novo Data Module e adicione um SQLDataSet, um DataSetProvider e um ClientDataSet. Veja os componentes dispostos na Figura 4.

 

 

Figura 4. Data Module para os componentes de pesquisa

Aperte Alt + F11 para abrir o editor Use unit. Escolha DM. Você deve estar perguntando: “Nos componentes de pesquisa, também preciso ter um trio para cada pesquisa?”. E a resposta é? Não.

 

Se vamos utilizar o ClientDataSet para pesquisar, não precisamos do trio, pois os outros componentes tem a responsabilidade de incluir dados no banco, como já comentamos. Precisamos apenas configurar os componentes, como fizemos antes (vincular os componentes via propriedades) e modificar uma propriedade do DataSetProvider para que o ClientDataSet possa gerenciar a consulta SQL para trazer os dados para o componente.

 

Altere para true a propriedade Options>poAllowCommandText do dspPesquisa. Agora, a consulta SQL para retornar os dados, vamos escrevê-la na propriedade CommandText do cdsPesquisaCliente. Note que não temos um editor como o SQLDataSet, mas podemos digitar o SQL.

Digite o seguinte comando:

 

select nCdCliente, sNmCliente

from CLIENTE

where UPPER(sNmCliente) like :sNmCliente

 

Veja que retornamos apenas dois campos e usamos o like, pois vamos fazer uma pesquisa parcial pelo nome do cliente. Configure o parâmetro para o tipo ftString.

Pesquisa parcial

Agora vamos mudar nossa tela de cadastro. Configure o DataSource para o cdsPesquisaCliente. No evento OnKeyDown do Edit, digite o código da Listagem 1.

 

Listagem 1. Executando a consulta com parâmetros

if (Key = VK_RETURN) then

begin

   DMPesquisa.cdsPesquisaCliente.Close;

   DMPesquisa.cdsPesquisaCliente.Params[0].AsString :=

     UpperCase('%'+ edtPesquisa.Text + '%');

   DMPesquisa.cdsPesquisaCliente.Open;

end;

 

Veja que verificamos se o usuário usou a tecla ENTER, para executar o código. A seguir, fechamos o ClientDataSet e preenchemos o parâmetro configurado. Note que como usamos o comando Upper no SQL, também precisamos repassar o valor digitado em maiúsculo para uma perfeita comparação.

 

É importante notar, o tipo do parâmetro (string). Precisamos configurar o tipo correto, então usamos o AsString. No ClientDataSet do cadastro, o parâmetro é do tipo inteiro, então, quando fizermos essa filtragem precisamos usar a configuração correta (AsInteger).

 

Por fim, chamamos o Open para mostrar os dados retornados. Execute a aplicação e faça pesquisas na aba. Ao entrar na aba e apertar ENTER, todos os registros são retornados. Poderíamos fazer uma restrição para que o usuário não possa fazer pesquisa sem digitar uma quantidade mínima de caracteres.

 

Isso auxilia, pois caso o cadastro possua muitos registros, o trafego da rede seria grande. O código seria:

 

if (Key = VK_RETURN) then

begin

   if Length(edtPesquisa.Text) < 3 then

      ShowMessage('Digite no mínimo 3 caracteres.')

   else

   ...

 

Digite algum valor e aperte ENTER e visualize os registros que atendem ao parâmetro digitado (Figura 5).

 

 

Figura 5. Cadastro com pesquisa auxiliar

 

Agora, precisamos configurar para que ao usuário dar um duplo clique no grid, ao escolher um registro, possamos filtrar os dados para o cadastro e mostrar o mesmo ao usuário. No evento OnDblClick do grid, adicione o código da Listagem 2.

 

Listagem 2. Filtrando o registro escolhido no grid

if (DMPesquisa.cdsPesquisaCliente.RecordCount > 0) then

begin

   DM.cdsCliente.Close;

   DM.cdsCliente.Params[0].AsInteger :=

     DMPesquisa.cdsPesquisaCliente.FieldByName('nCdCliente').AsInteger;

   DM.cdsCliente.Open;

 

   pgCadastro.ActivePage := tabDados;

end;

 

Primeiro, verificamos se existem registros no grid para executar a filtragem. Preenchemos o parâmetro do componente de cadastro, com o valor do código presente no componente de pesquisa. Por fim, mostramos a aba de cadastro. Execute e teste a aplicação (Figura 6).

 

 

Figura 6. Pesquisa e filtragem do cadastro

Modificando o cadastro de empregados

Você pode pensar, as modificações no cadastro de empregados têm as mesmas características do cadastro de clientes. Em parte sim. Precisamos criar a pesquisa, alterar a consulta do cadastro, criar parâmetro e alterar o layout.

 

Mas se você recordar, no cadastro de empregados, temos um relacionamento com o setor, onde adicionamos um ComboBox para o usuário escolher o setor. OK, o cadastro de setor é pequeno, não valeria a pena a modificação, mas nesse caso, vou mostrar a alteração para fins de conhecimento.

 

Vamos remover o controle (ComboBox) e vamos criar uma consulta auxiliar (com uma nova tela) para o usuário pesquisar o setor que deseja. Assim, nosso cadastro estará parametrizado, otimizando a performance do mesmo.

 

Precisamos fazer uma modificação na consulta de empregados, para trazer, o nome do setor, pois temos que mostrar o nome (caso o cadastro tenha relacionamento) para o usuário. A Listagem 3 mostra o novo comando SQL do dsEmpregado no DM.

 

Listagem 3. Alterando a consulta de empregado para retornar o setor

select

       EMPREGADO.nCdEmpregado,

       EMPREGADO.nCdSetor,

        EMPREGADO.nPcComissao,

        EMPREGADO.sNmEmpregado,

        EMPREGADO.tDtAdmissao,

        SETOR.sNmSetor

from EMPREGADO

INNER JOIN SETOR ON SETOR.nCdSetor = EMPREGADO.nCdSetor

where EMPREGADO.nCdEmpregado = :nCdEmpregado

 

Nota: Qualquer modificação feita no editor do SQL ou mesmo diretamente no comando, através da propriedade CommandText, o parâmetro deve ser reconfigurado, tanto no SQLDataSet, quanto no ClientDataSet.

 

Agora, precisamos configurar corretamente o Field do novo campo (sNmSetor), para que o dbExpress não tente atualizar o mesmo quando for salvar o registro. Desmarque todas as opções marcadas para o TField sNmSetor, assim, o dbExpress não tentará inserir/atualizar o mesmo.

 

Na tela de cadastro, adicione um DBText para mostrar o nome do setor (Figura 7).

 

 

Figura 7. Alterando o campo Setor no cadastro de empregado

Após as alterações, faça testes na aplicação para visualizar o nome do setor na pesquisa (Figura 8).

 

 

Figura 8. Mostrando o nome do setor no cadastro

Agora, e quando quisermos alterar o setor? Vamos criar uma tela de pesquisa de setor. Crie um novo formulário e adicione os seguintes componentes: RadioGroup, DBGrid, Edit, Labels. Monte o formulário conforme a Figura 9.

 

 

Figura 9. Tela de pesquisa de setor

Crie um componente para pesquisa de setor, semelhante aos de pesquisa de cliente e empregado. Vincule o componente ao DataSource da tela, e esse ao DBGrid. No evento OnKeyDown do Edit, digite o código da Listagem 4.

 

Listagem 4. Código para pesquisa de setores

if Key = VK_RETURN then

begin

  DMPesquisa.cdsPesquisaSetor.Close;

  DMPesquisa.cdsPesquisaSetor.CommandText := '';

 

  if RadioGroup1.ItemIndex = 0 then

  begin

    if IsNumero(edtPesquisa.Text) then

      DMPesquisa.cdsPesquisaSetor.CommandText :=

        'select nCdSetor, sNmSetor from SETOR where nCdSetor = ' +

        edtPesquisa.Text

    else

      ShowMessage('Digite um número para pesquisar por código');

  end

  else

  begin

    if Length(edtPesquisa.Text) < 3 then

      ShowMessage('Digite no mínimo 3 caracteres.')

    else

      DMPesquisa.cdsPesquisaSetor.CommandText :=

        'select nCdSetor, sNmSetor from SETOR where UPPER(sNmSetor) like ' +

        UpperCase(QuotedStr('%' + edtPesquisa.Text + '%'));

  end;

 

  DMPesquisa.cdsPesquisaSetor.Open;

end;

 

Note que de acordo com o que for escolhido no RadioGroup, mudamos o conteúdo do SQL passado para a propriedade CommandText. Para a pesquisa parcial (pelo nome do setor), implementamos uma validação como já mostramos anteriormente. O comando QuotedStr, adiciona aspas simples ('') na consulta SQL, pois estamos trabalhando com string.

 

Para o código, criamos uma function que retorna se o valor digitado é um número para que não ocorra erro quando pesquisarmos por código, sendo o que foi digitado é uma string. Veja na Listagem 5 o código do IsNumero.

 

Listagem 5. Função para validar se o valor é número

function IsNumero(sNumero: string): boolean;

begin

  try

    StrToInt(sNumero);

    Result := true;

  except

    Result := false;

  end;

end;

 

Qual a lógica da função. Executamos o comando que transforma uma string em número, dentro de um bloco try...exception, que caso ocorra erro, o código que será executado estará dentro do except. Assim, se nenhum erro ocorrer, o result será verdadeiro, senão, será falso.

Agora, no OnDblClick do grid para fecharmos o formulário com o seguinte código:

 

if DMPesquisa.cdsPesquisaSetor.RecordCount > 0 then

begin

  Close;

  ModalResult := mrOk;

end;

 

Verificamos se existem registros no componente de pesquisa, e depois o primeiro código fecha o formulário de pesquisa, já o segundo, indica o resultado que será verificado no formulário que chamará a tela de pesquisa.

Para entender, adicione um botão no cadastro de empregados. Adicione o código da Listagem 6.

 

Listagem 6. Código para chamar o formulário de pesquisa

Application.CreateForm(TfrmPesquisarSetor, frmPesquisarSetor);

try

  frmPesquisarSetor.ShowModal;

  if frmPesquisarSetor.ModalResult = mrOk then

  begin

    DM.cdsEmpregado.Edit;

    DM.cdsEmpregadosNmSetor.AsString :=

      DMPesquisa.cdsPesquisaSetor.FieldByName('sNmSetor').AsString;

    DM.cdsEmpregadonCdSetor.AsInteger :=

      DMPesquisa.cdsPesquisaSetor.FieldByName('nCdSetor').AsInteger;

  end;

finally

  frmPesquisarSetor.Free;

end;

 

Após a chamada do formulário (ShowModal) verificamos o retorno do formulário através da propriedade ModalResult. Se o usuário não escolher nenhum registro, fechar o formulário, não precisamos executar o código para alterar o nome do setor.

 

Caso o mesmo escolha um registro no grid, vamos chamar o método Edit do ClientDataSet de cadastro e atribuindo os valores para o nome do setor e o código do setor do cadastro de empregados. Veja na Figura 10 temos a aplicação em execução.

 

 

Figura 10. Alterando o setor com a pesquisa auxiliar

Finalizando as alterações

Pra finalizar, precisamos implementar os botões para inserir um novo, salvar ou excluir os registros da tela. Veja na Figura 11 como ficará o layout dos cadastros.

 

 

Figura 11. Botões de cadastro

 

Na Listagem 7 temos o código dos botões.

 

Listagem 7. Código dos botões

Novo

DM.cdsEmpregado.Insert;

 

Salvar

try

  DM.cdsEmpregado.Post;

  ShowMessage('Registro salvo com sucesso.');

except

  on E: Exception do

  ShowMessage('Ocorreu um erro: ' + E.Message);

end;

 

Excluir

if (MessageDlg('Deseja excluir?', mtConfirmation, [mbYes, mbNo], 0) = mrYes) then

  DM.cdsEmpregado.Delete;

 

O botão Novo simplesmente chama o Insert do ClientDataSet. Já no Salvar, colocamos um bloco try...except para que caso ocorra algum erro, uma mensagem com  a descrição do erro, seja mostrada ao usuário.

 

O Excluir pede a confirmação da exclusão para o usuário e caso afirmativo, exclui o registro. Para excluir o registro no banco, precisamos chamar o mesmo código que usamos no evento AfterPost visto no artigo anterior.

 

No DM, adicione o seguinte código no evento AfterDelete do cdsEmpregado (faça o mesmo para o cdsCliente):

 

cdsEmpregado.ApplyUpdates(0);

 

Faça todos os testes na apliacação: novo registro, salve e exclua. Faça as modificações no outro cadastro.

Novo cadastro e o que vem pela frente

Agora que já aprendeu como fazer um cadastro simples parametrizado e como usar pesquisa auxiliar no cadastro, implemente o mesmo para a tabela PRODUTO. Adiantando o que teremos no próximo artigo, vamos criar um cadastro máster/detail, com o cadastro de vendas e seus respectivos itens.

 

Lembrando, para incluir os registros da tabela ITENS, precisamos ter o código da venda, presente na tabela VENDA, ou seja, precisamos incluir uma venda, recuperar seu código e inserir o mesmo quando salvar o item.

Como fazer isso? Dados em memória com o ClientDataSet. Além disso, precisamos de uma transação nisso, pois não podemos ter ITENS sem a VENDA e nem a VENDA sem seus ITENS. Veja que temos muito a aprender ainda.

 

Você deve estar perguntando: “Luciano, você sempre fala que o Delphi é produtivo, tem facilidades da programação OO, mas pelo que já vi até agora, tivemos dois cadastros (e teremos o terceiro), onde precisamos refazer layout e algumas validações, tipo replicando código”.

 

Veremos nos próximos artigos algo bastante interessante e produtivo para aplicações com Delphi, a facilidade que temos em criar telas de cadastros: a herança visual. Apenas para adiantar a ideia: teremos uma tela de cadastro padrão, com um layout (por exemplo, as abas e botões) comum para qualquer cadastro.

 

Nessa tela padrão, teremos código bastante genérico para ser usado independente de estarmos no cadastro de cliente, empregado ou qualquer outro. Vale a pena esperar.

Conclusões

Vimos nesse artigo, como utilizar de maneira correta, a criação de cadastros parametrizados no Delphi para aplicações cliente/server. No próximo artigo, vamos criar uma característica muito comum em aplicações, o cadastro máster/detail.

Um grande abraço a todos e até a próxima!