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:
[sourcecode language=”delphi”]
procedure TfrmMain.btnTesteClick(Sender: TObject);
begin
frmTesteAtributos := TfrmTesteAtributos.create(self);
try
frmTesteAtributos.showmodal;
finally
FreeAndNil(frmTesteAtributos);
end;
end;
[/sourcecode]
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 ( 😯 ) 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:
[sourcecode language=”delphi”]
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;
[/sourcecode]
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 😀
- 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:
[sourcecode language=”delphi”]
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;
[/sourcecode]
Muito parecido com incluir, apenas alteramos a chamada para Salvar (linha 18).
No botão excluir, coloque:
[sourcecode language=”delphi”]
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;
[/sourcecode]
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:
[sourcecode language=”delphi”]
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;
[/sourcecode]
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:
[sourcecode language=”delphi”]
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;
[/sourcecode]
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.
É 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á!