Olá Pessoal
Hoje iremos analisar as classes criadas e refatorar o que for necessário. Só depois, iremos para a implementação da classe do DbExpress que eu havia prometido no post anterior. Assim, evitamos que problemas existentes agora persistam nas próximas classes.
Desde o início nos preocupamos em seguir os princípios da Orientação a Objetos (OO) em nosso projeto. Porém, estar totalmente dentro destes princípios por vezes pode se tornar uma tarefa não tão simples, o que poderá fazer com que um código que não se enquadre nos “bons costumes” OO passe despercebido aos nossos olhos em meio aos inúmeros métodos e classes por nós criados. Por isso, sempre procurar melhorar o código (refatorar) é a melhor maneira para tentar atingir nosso objetivo. E é isso que faremos adiante.
Dando início à análise, tem uma coisa que não está cheirando bem nos métodos CRUD: Inserir, Excluir, Salvar e Buscar. Isso ficou ainda mais evidente com a criação da segunda classe, a TDaoIBX. Se focarmos no método Inserir das duas classes (TDaoUib e TDaoIbx), percebemos uma repetição de código exagerada:
Princípio OO: Encapsule o que varia
Primeiro, só pra constar e não deixar qualquer dúvida, o método Inserir tem o seguinte objetivo:
Gerar uma string SQL para a inserção dos dados na tabela.
Desta forma, o padrão Sql de inserção segue o seguinte formato:
- Insert into Tabela (campo-1, campo-2, campo-3…) values (:campo-1, :campo-2, :campo-3…);
Veja que não tem dados específicos do componente de acesso, ou seja, trata-se apenas de uma string. Portanto, não precisamos replicar o código do SQL em todas as classes de conexão, a não ser que em determinada classe o padrão seja diferente deste. Neste caso, bastará um override no método, visto que o mesmo é virtual. Até o momento, é suficiente dizer que o padrão é o descrito acima.
Entendido qual o objetivo do método, iremos agora retirar os códigos SQL dos métodos CRUD, movendo-os para a classe base, ou seja, nossa classe abstrata TDaoBase . Vamos lá!
Abra Base.pas e localize a classe TDaoBase. Em protected, adicione quatro novos métodos:
[sourcecode language=”Delphi”]
…
protected
//geração do sql padrao
function GerarSqlInsert (ATabela: TTabela; TipoRtti: TRttiType): string; virtual;
function GerarSqlUpdate (ATabela: TTabela; TipoRtti: TRttiType): string; virtual;
function GerarSqlDelete (ATabela: TTabela): string; virtual;
function GerarSqlSelect (ATabela: TTabela): string; virtual;
…
[/sourcecode]
Ctrl+Shift+C para implementar os métodos. Abaixo, métodos implementados:
[sourcecode language=”Delphi”]
function TDaoBase.GerarSqlDelete(ATabela: TTabela): string;
var
Campo, Separador: string;
ASql : TStringList;
begin
ASql := TStringList.Create;
try
with ASql do
begin
Add(‘Delete from ‘ + PegaNomeTab(ATabela));
Add(‘Where’);
Separador := ”;
for Campo in PegaPks(ATabela) do
begin
Add(Separador + Campo + ‘= :’ + Campo);
Separador := ‘ and ‘;
end;
end;
Result := ASql.Text;
finally
ASql.Free;
end;
end;
function TDaoBase.GerarSqlInsert(ATabela: TTabela; TipoRtti: TRttiType): string;
var
Separador: string;
ASql : TStringList;
PropRtti: TRttiProperty;
begin
ASql := TStringList.Create;
try
with ASql do
begin
Add(‘Insert into ‘ + PegaNomeTab(ATabela));
Add(‘(‘);
//campos da tabela
Separador := ”;
for PropRtti in TipoRtti.GetProperties do
begin
Add(Separador + PropRtti.Name);
Separador := ‘,’;
end;
Add(‘)’);
//parâmetros
Add(‘Values (‘);
Separador := ”;
for PropRtti in TipoRtti.GetProperties do
begin
Add(Separador + ‘:’ + PropRtti.Name);
Separador := ‘,’;
end;
Add(‘)’);
end;
Result := ASql.text;
finally
ASql.Free;
end;
end;
function TDaoBase.GerarSqlSelect(ATabela: TTabela): string;
var
Campo, Separador: string;
ASql : TStringList;
begin
ASql := TStringList.Create;
try
with ASql do
begin
Add(‘Select * from ‘ + PegaNomeTab(ATabela));
Add(‘Where’);
Separador := ”;
for Campo in PegaPks(ATabela) do
begin
Add(Separador + Campo + ‘= :’ + Campo);
Separador := ‘ and ‘;
end;
end;
Result := ASql.Text;
finally
ASql.Free;
end;
end;
function TDaoBase.GerarSqlUpdate(ATabela: TTabela; TipoRtti: TRttiType): string;
var
Campo, Separador: string;
ASql : TStringList;
PropRtti: TRttiProperty;
begin
ASql := TStringList.Create;
try
with ASql do
begin
Add(‘Update ‘ + PegaNomeTab(ATabela));
Add(‘set’);
//campos da tabela
Separador := ”;
for PropRtti in TipoRtti.GetProperties do
begin
Add(Separador + PropRtti.Name + ‘=:’+PropRtti.Name);
Separador := ‘,’;
end;
Add(‘where’);
//parâmetros da cláusula where
Separador := ”;
for Campo in PegaPks(ATabela) do
begin
Add(Separador+ Campo + ‘= :’ + Campo);
Separador := ‘ and ‘;
end;
end;
Result := ASql.text;
finally
ASql.Free;
end;
end;
[/sourcecode]
Basicamente, movi a parte de cada método que tratava da geração da string SQL. Feito isso, você pode estar curioso com relação aos métodos CRUD em TDaoUib e TDaoIbx. Não se aflija, segue abaixo métodos de TDaoUib:
[sourcecode language=”Delphi”]
function TDaoUib.Excluir(ATabela: TTabela): Integer;
var
Comando: TFuncReflexao;
begin
//crio uma variável do tipo TFuncReflexao – um método anônimo
Comando := function(ACampos: TCamposAnoni): Integer
var
Campo: string;
PropRtti: TRttiProperty;
begin
Qry.Close;
Qry.SQL.Clear;
Qry.SQL.Text := GerarSqlDelete(ATabela);
//percorrer todos os campos da chave primária
for Campo in PegaPks(ATabela) do
begin
// setando os parâmetros
for PropRtti in ACampos.TipoRtti.GetProperties do
if CompareText(PropRtti.Name, Campo) = 0 then
begin
ConfiguraParametro(PropRtti, Campo, ATabela, Qry);
end;
end;
Result := ExecutaQuery;
end;
//reflection da tabela e execução da query preparada acima.
Result := ReflexaoSQL(ATabela, Comando);
end;
function TDaoUib.Inserir(ATabela: TTabela): Integer;
var
Comando: TFuncReflexao;
begin
Result := 0;
Comando := function(ACampos: TCamposAnoni): Integer
var
Campo: string;
PropRtti: TRttiProperty;
begin
with Qry do
begin
close;
SQL.clear;
SQL.Text := GerarSqlInsert(ATabela, ACampos.TipoRtti);
//valor dos parâmetros
for PropRtti in ACampos.TipoRtti.GetProperties do
begin
Campo := PropRtti.Name;
ConfiguraParametro(PropRtti, Campo, ATabela, Qry);
end;
end;
Result := ExecutaQuery;
end;
//reflection da tabela e execução da query preparada acima.
Result := ReflexaoSQL(ATabela, Comando);
end;
function TDaoUib.Salvar(ATabela: TTabela): Integer;
var
Comando: TFuncReflexao;
begin
Result := 0;
Comando := function(ACampos: TCamposAnoni): Integer
var
Campo: string;
PropRtti: TRttiProperty;
begin
with Qry do
begin
close;
sql.Clear;
sql.Text := GerarSqlUpdate(ATabela, Acampos.TipoRtti);
//valor dos parâmetros
for PropRtti in ACampos.TipoRtti.GetProperties do
begin
Campo := PropRtti.Name;
ConfiguraParametro(PropRtti, Campo, ATabela, Qry);
end;
end;
Result := ExecutaQuery;
end;
//reflection da tabela e execução da query preparada acima.
Result := ReflexaoSQL(ATabela, Comando);
end;
function TDaoUib.Buscar(ATabela: TTabela): Integer;
var
Comando: TFuncReflexao;
Dados: TUIBQuery;
begin
Dados := TUIBQuery.Create(nil);
try
//crio uma variável do tipo TFuncReflexao – um método anônimo
Comando := function(ACampos: TCamposAnoni): Integer
var
Campo: string;
PropRtti: TRttiProperty;
begin
with Dados do
begin
Database := FDatabase;
Transaction := FTransaction;
sql.Text := GerarSqlSelect(ATabela);
for Campo in ACampos.PKs do
begin
// setando os parâmetros
for PropRtti in ACampos.TipoRtti.GetProperties do
if CompareText(PropRtti.Name, Campo) = 0 then
begin
ConfiguraParametro(PropRtti, Campo, ATabela, Dados);
end;
end;
Open;
Result := Fields.RecordCount;
if Result > 0 then
begin
for PropRtti in ACampos.TipoRtti.GetProperties do
begin
Campo := PropRtti.Name;
SetaDadosTabela(PropRtti, Campo, ATabela, Dados);
end;
end;
end;
end;
//reflection da tabela e abertura da query preparada acima.
Result := ReflexaoSQL(ATabela, Comando);
finally
Dados.Free;
end;
end;
[/sourcecode]
Note que, tudo que era relacionado à formatação da string SQL foi retirado e em seu lugar foi colocado os novos métodos da classe Base. O mesmo deverá ser feito para a classe TDaoIbx.
Neste post não deixarei os fontes, visto que ainda falta finalizar as mudanças iniciadas acima.
No próximo, continuaremos os trabalhos de refatoração do código. Até lá.
Olá Luiz,
Não vai mais dá continuidade no artigo?
Grato