Eis que chega o grande momento! Iremos testar a Inclusão, Alteração e Exclusão da nossa classe TDaoUib. Até aqui, apenas criamos nossos métodos, mas na prática, pouca coisa foi visto.

Alterando o Projeto para os Testes

Relembrando, nós temos um form chamado frmMain:

Ele possui um componente de conexão à base de dados, TUIBDataBase, e uma transação, TUIBTransaction.

Além do frmMain, temos o formulário criado para teste dos atributos, o frmTesteAtributos:

Altere novamente o auto-create forms. Deixe apenas o frmMain no auto-create:

Altere o caption do botão para “Teste”:

No clique do botão, vamos chamar o formulário de teste de atributos:

procedure TfrmMain.btnTesteClick(Sender: TObject);
begin
  frmTesteAtributos := TfrmTesteAtributos.create(self);
  try
    frmTesteAtributos.showmodal;
  finally
    FreeAndNil(frmTesteAtributos);
  end;
end;

Lembre-se de adicionar a unidade ufrmTesteAtributos à cláusula uses do frmMain.

Este formulário principal terá a função, além do óbvio, de ser um receptáculo ( :shock: ) para os componentes database. Se você quiser, poderá utilizar um datamodule, que é o mais correto. Como estou utilizando apenas para testes, não vejo motivo para tal.

No formulário frmTesteAtributos, insira mais três botões:

Adicione no uses, abaixo de implementation (para não dar referência circular), a unidade ufrmMain e no clique do botão Inserir, coloque:

procedure TfrmTesteAtributos.btnInserirClick(Sender: TObject);
var
  ATab: TTeste;
  Dao: IDaoBase;
  Registros: Integer;
begin
  ATab := TTeste.Create;
  try
    Dao := TDaoUib.Create(frmMain.UIBDataBase1, frmMain.UIBTransaction1);
    with ATab do
    begin
      id := 1;
      Estado := 'MA';
      Descricao := 'MARANHÃO';
      Habitantes := 6569683;
      RendaPerCapta := 319;
    end;
    Registros := Dao.Inserir(ATab);
    Memo1.Lines.Add(Format('Registro inserido: %d', [Registros]));
    Memo1.Lines.Add(Format('id: %d, nome: %s',[ATab.Id, atab.Descricao]));
  finally
    ATab.Free;
  end;
end;

Analisando o código:

  • Linha 7, criamos o nosso objeto do tipo TTeste; adicione ao uses à unidade Teste.
  • Linha 9, criamos um objeto TDaoUib. Note que na declaração da variável (linha 4) definimos como sendo do tipo IDaoBase (nossa interface). Para funcionar, adicione à cláusula uses a unidade Base e DaoUib. Não se preocupe, pois nos próximos artigos iremos abstrair de tal forma, se é que me entende, que não será necessário adicionar tantas unidades ao uses. Aguarde e verá! Mas para o momento, elas são necessárias.
  • Linhas 12-16, setamos os valores das propriedades do nosso objeto (ATab) da classe Teste.
  • Linha 18, a mágica acontece! Inserimos os registros na base de dados. O retorno será a quantidade de registros afetados, que no caso será 1 registro. “Adeus ao inserts! Viva!” clap clap clap :D
  • Linha 19 e 20, mostramos o resultado no memo.
  • Linha 22, destruímos o objeto ATab. Mas e o Dao, não será destruído??? Lembra que declaramos ele como sendo IDaoBase e que na construção desta interface utilizamos TInterfacedObject? Pois bem, o objeto será automaticamente destruído, sem necessitar de nossa intervenção.

Em salvar, coloque:

procedure TfrmTesteAtributos.btnSalvarClick(Sender: TObject);
var
  ATab: TTeste;
  Dao: IDaoBase;
  Registros: Integer;
begin
  ATab := TTeste.Create;
  try
    Dao := TDaoUib.Create(frmMain.UIBDataBase1, frmMain.UIBTransaction1);
    with ATab do
    begin
      id := 1;
      Estado := 'MA';
      Descricao := 'MARANHÃO (ALTERADO)';
      Habitantes := 6569683;
      RendaPerCapta := 319;
    end;
    Registros := Dao.Salvar(ATab);
    Memo1.Lines.Add(Format('Registro inserido: %d', [Registros]));
    Memo1.Lines.Add(Format('id: %d, nome: %s',[ATab.Id, atab.Descricao]));
  finally
    ATab.Free;
  end;
end;

Muito parecido com incluir, apenas alteramos a chamada para Salvar (linha 18).

No botão excluir, coloque:

procedure TfrmTesteAtributos.btnExcluirClick(Sender: TObject);
var
  ATab: TTeste;
  Dao: IDaoBase;
  Registros: Integer;
begin
  ATab := TTeste.Create;
  try
    Dao := TDaoUib.Create(frmMain.UIBDataBase1, frmMain.UIBTransaction1);
    ATab.Id := 1;
    Registros := Dao.Excluir(ATab);
    Memo1.Lines.Add(Format('Registro excluido: %d', [Registros]));
  finally
    ATab.Free;
  end;
end;

Nada de novo aqui também, apenas definimos o valor da chave primária (linha 10) e chamamos o método Excluir do TDaoUib (linha 11).

Pronto! Passageiros, sentem em suas poltronas e apertem os cintos…

Colocando código em ação!

Compile e execute. Ao abrir o formulário principal, clique em Teste para chamar o formulário de teste dos atributos:

Clicando no botão inserir, obtemos…. BOOOOOOOMMMMMMM:

Sempre que algo assim acontecer, antes do desespero, analise o erro. O pulo do gato está na quarta linha da exceção: Incompatible column/host variable data type.

Nada como utilizar o debug do Delphi nessas horas. Mas aí vem a pergunta: devo ir marcando breakpoints em todos os métodos da classe? Existem casos que sim, você tem que ir testando os métodos, porém, aqui não!

Me diga: em quais partes de TDaoUib o data type é manipulado?

Só existe um lugar (pois somos organizados) onde isso foi feito: no método ConfigParametro!

Já pensou se tivéssemos espalhado os códigos que se encontram neste método por toda a classe? Para corrigir, que trabalhão, hein?!?

Então, vamos lá:

Marque um breakpoint no for que configura os valores dos parâmetros no método Inserir:

Clique novamente no botão inserir… irá parar no breakpoint. Dê F8 até a linha de execução passar pela variável Campo, ou seja, quando estiver sobre ConfigParametro. Passe o mouse sobre a variável Campo para ver o nome da propriedade que está sendo tratada no momento:

Veja que na primeira vez, a propriedade é “Id”. Vá executando F8 e observando as propriedades, até que o erro ocorra. Será na última propriedade observada onde se encontrará o erro.

Bom, assim detectamos que o erro está na propriedade “Data”. Faça novamente o procedimento até chegar no processamento desta propriedade, porém quando cair na linha do ConfigParametro, em vez do F8, utilize F7. Iremos entrar dentro deste procedimento:

Note que ao passarmos o mouse sobre TypeKind, o Delphi nos mostra o tipo de data type da propriedade “Data”, que é: tkFloat.

Aí está a prova do que eu disse anteriormente, em outro artigo, que o formato data é do tipo Float.

E agora, José? Complicou!

Não, pelo contrário. Resolver isso é moleza, bastará apenas fazer um teste para ver que tipo de variável está sendo tratada. Então, alterando ConfigParametro, temos:

procedure TDaoUib.ConfigParametro(AQuery: TUIBQuery; AProp: TRttiProperty;
  ACampo: string; ATabela: TTabela);
begin
  with AQuery do
  begin
    case AProp.PropertyType.TypeKind of
      tkInt64,
      tkInteger:
      begin
        Params.ByNameAsInteger[ACampo] := AProp.GetValue(ATabela).AsInteger;
      end;
      tkChar,
      tkString,
      tkUString:
      begin
        Params.ByNameAsString[ACampo] := AProp.GetValue(ATabela).AsString;
      end;
      tkFloat:
      begin
        if CompareText(AProp.PropertyType.Name, 'TDateTime') = 0 then
         Params.ByNameAsDateTime[ACampo] := AProp.GetValue(ATabela).AsType<TDateTime>
        else
         Params.ByNameAsCurrency[ACampo] := AProp.GetValue(ATabela).AsCurrency;
      end;
      tkVariant:
      begin
        Params.ByNameAsVariant[ACampo] := AProp.GetValue(ATabela).AsVariant;
      end;
    else
      raise Exception.Create('Tipo de campo não conhecido: ' + AProp.PropertyType.ToString);
    end;
  end;

Em resumo, se o nome do tipo da propriedade for “TDateTime” (linha 20), configuramos o parâmetro para este formato. Caso contrário, processamos normalmente como sendo um “Currency” (preferência minha).

Marque um breakpoint nesta linha e desmarque os pontos marcados anteriormente. Deixe apenas este. Feche o programa e o execute novamente. Dê F8 e veja que a linha de execução cai corretamente na linha logo abaixo, formatando o parâmetro como data:

Se você continuar executando F8, veja que novamente a comparação será efetuada, porém, desta vez, cairá sobre a segunda opção, ou seja, existe somente uma propriedade data e as demais são do tipo float mesmo.

Após a execução, vemos o seguinte resultado:

Visualizando tabela no IbExpert:

Observação: Será necessário fechar o programa de teste para que os dados apareçam na base de dados, visto que ainda não estamos utilizando as transações (abrindo, comitando ou dando rollback).

Veja que no clique do botão inserir e nem no salvar, não informamos uma data. Agora que o processo está ok, no botão salvar informe uma data:

procedure TfrmTesteAtributos.btnSalvarClick(Sender: TObject);
var
  ATab: TTeste;
  Dao: IDaoBase;
  Registros: Integer;
begin
  ATab := TTeste.Create;
  try
    Dao := TDaoUib.Create(frmMain.UIBDataBase1, frmMain.UIBTransaction1);
    with ATab do
    begin
      id := 1;
      Estado := 'MA';
      Data   := Now;  // <-- agora já é possível tratar campos no formato data...
      Descricao := 'MARANHÃO (ALTERADO)';
      Habitantes := 6569683;
      RendaPerCapta := 319;
    end;
    Registros := Dao.Salvar(ATab);
    Memo1.Lines.Add(Format('Registro inserido: %d', [Registros]));
    Memo1.Lines.Add(Format('id: %d, nome: %s',[ATab.Id, atab.Descricao]));
  finally
    ATab.Free;
  end;
end;

Feche, compile e execute o programa novamente. E depois, clique em salvar:

Feche o programa e abra a tabela novamente no IbExpert (ou qualquer outro software do tipo):

Perceba que a data e a descrição foram corretamente alteradas.

E por fim, o botão Excluir:

É isso!

No próximo artigo iremos criar classes que nos permitirão trocar um componente por outro sem tantos traumas. Além disso, diminuiremos a dependência existente entre as classes. Utilizaremos para isso Generics, Interfaces e o Padrão de Projeto Singleton. Até lá!

Desenvolvedor de software desde 1995. Em 1998, abriu sua própria empresa, a Lukas Sistemas, desde então passou a atender diversas empresas, principalmente autopeças. Apaixonado por Delphi, porém não o impede de flertar com outras linguagens sempre que possível. Mora na cidade de Balsas/MA com sua esposa e dois filhos.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.