Olá! Saudades?
Ok, Ok, Estou em débito com vocês, caríssimos leitores! Estive realmente assoberbado aqui e acabei passando um longo tempo sem atualizar o nosso “projetim“. Ainda me encontro com a água no pescoço, mas juntei forças para mais um post.
Na última atualização, foi definido que passaríamos a utilizar generics para o nosso projeto. Agora irei demonstrar como será simples utilizar outro set de componentes, ou seja, estaremos mudando de UIB para IBX. Para isso, devemos implementar uma nova classe, a TDaoIbx.
Abra o explorer, localize a pasta classes e copie o arquivo DaoUib.pas, cole e renomeie para DaoIbx.pas:
Abra DaoIbx.pas no Delphi e troque tudo que for relacionado ao outro componente para IBX, conforme código abaixo:
[sourcecode language=”delphi”]
unit DaoIbx;
interface
uses Base, Rtti, Atributos, system.SysUtils, System.Classes, IB,
IBQuery, IBDatabase;
type
TDaoIbx = class(TDaoBase)
private
// conexao com o banco de dados
FDatabase: TIBDatabase;
// transação para crud
FTransaction: TIbTransaction;
// transação para consultas
FTransQuery: TIBTransaction;
protected
// métodos responsáveis por setar os parâmetros
procedure QryParamInteger(ARecParams: TRecParams); override;
procedure QryParamString(ARecParams: TRecParams); override;
procedure QryParamDate(ARecParams: TRecParams); override;
procedure QryParamCurrency(ARecParams: TRecParams); override;
procedure QryParamVariant(ARecParams: TRecParams); override;
//métodos para setar os variados tipos de campos
procedure SetaCamposInteger(ARecParams: TRecParams); override;
procedure SetaCamposString(ARecParams: TRecParams); override;
procedure SetaCamposDate(ARecParams: TRecParams); override;
procedure SetaCamposCurrency(ARecParams: TRecParams); override;
function ExecutaQuery: Integer; override;
procedure FechaQuery; override;
public
//query para execução dos comandos crud
Qry: TIBQuery;
constructor Create(ADatabaseName: string);
function Inserir(ATabela: TTabela): Integer; override;
function Salvar(ATabela: TTabela): Integer; override;
function Excluir(ATabela: TTabela): Integer; override;
function Buscar(ATabela:TTabela): Integer; override;
function InTransaction: Boolean; override;
procedure StartTransaction; override;
procedure Commit; override;
procedure RollBack; override;
end;
implementation
{ TDaoIbx }
uses Vcl.forms, dialogs, System.TypInfo;
constructor TDaoIbx.Create(ADatabaseName: string);
begin
inherited Create;
FDatabase := TIBDatabase.Create(Application);
//configurações iniciais da conexão
with FDatabase do
begin
DatabaseName := ADatabaseName;
Params.Add(‘user_name=sysdba’);
Params.Add(‘password=masterkey’);
LoginPrompt := false;
Connected := True;
end;
//configurações iniciais da transacao para consultas
FTransQuery := TIBTransaction.Create(Application);
with FTransQuery do
begin
DefaultDatabase := FDatabase;
Params.Add(‘read_committed’);
Params.Add(‘rec_version’);
Params.Add(‘nowait’);
end;
FDatabase.DefaultTransaction := FTransQuery;
//configurações iniciais da transacao para crud
FTransaction := TIBTransaction.Create(Application);
with FTransaction do
begin
DefaultDatabase := FDatabase;
Params.Add(‘read_committed’);
Params.Add(‘rec_version’);
Params.Add(‘nowait’);
end;
Qry := TIBQuery.Create(Application);
Qry.DataBase := FDatabase;
Qry.Transaction := FTransaction;
end;
procedure TDaoIbx.QryParamCurrency(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
TIBQuery(Qry).ParamByName(Campo).AsCurrency := Prop.GetValue(Tabela).AsCurrency;
end;
end;
procedure TDaoIbx.QryParamDate(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
TIBQuery(Qry).ParamByName(Campo).AsDateTime := Prop.GetValue(Tabela).AsType<TDateTime>;
end;
end;
procedure TDaoIbx.QryParamInteger(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
TIBQuery(Qry).ParamByName(Campo).AsInteger := Prop.GetValue(Tabela).AsInteger;
end;
end;
procedure TDaoIbx.QryParamString(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
TIBQuery(Qry).ParamByName(Campo).AsString := Prop.GetValue(Tabela).AsString;
end;
end;
procedure TDaoIbx.QryParamVariant(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
TIBQuery(Qry).ParamByName(Campo).Value := Prop.GetValue(Tabela).AsVariant;
end;
end;
procedure TDaoIbx.SetaCamposCurrency(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
Prop.SetValue(Tabela, TIBQuery(Qry).FieldByName(Campo).AsCurrency);
end;
end;
procedure TDaoIbx.SetaCamposDate(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
Prop.SetValue(Tabela, TIBQuery(Qry).FieldByName(Campo).AsDateTime);
end;
end;
procedure TDaoIbx.SetaCamposInteger(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
Prop.SetValue(Tabela, TIBQuery(Qry).FieldByName(Campo).AsInteger);
end;
end;
procedure TDaoIbx.SetaCamposString(ARecParams: TRecParams);
begin
inherited;
with ARecParams do
begin
Prop.SetValue(Tabela, TIBQuery(Qry).FieldByName(Campo).AsString);
end;
end;
function TDaoIbx.InTransaction: Boolean;
begin
Result := FTransaction.InTransaction;
end;
procedure TDaoIbx.StartTransaction;
begin
FTransaction.StartTransaction;
end;
procedure TDaoIbx.RollBack;
begin
FTransaction.RollBack;
end;
procedure TDaoIbx.Commit;
begin
FTransaction.Commit;
end;
procedure TDaoIbx.FechaQuery;
begin
Qry.Close;
Qry.SQL.Clear;
end;
function TDaoIbx.ExecutaQuery: Integer;
begin
with Qry do
begin
Prepare();
ExecSQL;
Result := RowsAffected;
end;
end;
function TDaoIbx.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
FechaQuery;
with Qry do
begin
sql.Add(‘Delete from ‘ + ACampos.NomeTabela);
sql.Add(‘Where’);
//percorrer todos os campos da chave primária
ACampos.Sep := ”;
for Campo in ACampos.PKs do
begin
sql.Add(ACampos.Sep+ Campo + ‘= :’ + Campo);
ACampos.Sep := ‘ and ‘;
// 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;
end;
Result := ExecutaQuery;
end;
//reflection da tabela e execução da query preparada acima.
Result := ReflexaoSQL(ATabela, Comando);
end;
function TDaoIbx.Inserir(ATabela: TTabela): Integer;
var
Comando: TFuncReflexao;
begin
Comando := function(ACampos: TCamposAnoni): Integer
var
Campo: string;
PropRtti: TRttiProperty;
begin
FechaQuery;
with Qry do
begin
sql.Add(‘Insert into ‘ + ACampos.NomeTabela);
sql.Add(‘(‘);
//campos da tabela
ACampos.Sep := ”;
for PropRtti in ACampos.TipoRtti.GetProperties do
begin
SQL.Add(ACampos.Sep + PropRtti.Name);
ACampos.Sep := ‘,’;
end;
sql.Add(‘)’);
//parâmetros
sql.Add(‘Values (‘);
ACampos.Sep := ”;
for PropRtti in ACampos.TipoRtti.GetProperties do
begin
SQL.Add(ACampos.Sep + ‘:’ + PropRtti.Name);
ACampos.Sep := ‘,’;
end;
sql.Add(‘)’);
//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 TDaoIbx.Salvar(ATabela: TTabela): Integer;
var
Comando: TFuncReflexao;
begin
Comando := function(ACampos: TCamposAnoni): Integer
var
Campo: string;
PropRtti: TRttiProperty;
begin
FechaQuery;
with Qry do
begin
sql.Add(‘Update ‘ + ACampos.NomeTabela);
sql.Add(‘set’);
//campos da tabela
ACampos.Sep := ”;
for PropRtti in ACampos.TipoRtti.GetProperties do
begin
SQL.Add(ACampos.Sep + PropRtti.Name + ‘=:’+PropRtti.Name);
ACampos.Sep := ‘,’;
end;
sql.Add(‘where’);
//parâmetros da cláusula where
ACampos.Sep := ”;
for Campo in ACampos.PKs do
begin
sql.Add(ACampos.Sep+ Campo + ‘= :’ + Campo);
ACampos.Sep := ‘ and ‘;
end;
//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 TDaoIbx.Buscar(ATabela: TTabela): Integer;
var
Comando: TFuncReflexao;
Dados: TIBQuery;
begin
Dados := TIBQuery.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;
sql.Add(‘select * from ‘ + ACampos.NomeTabela);
sql.Add(‘Where’);
//percorrer todos os campos da chave primária
ACampos.Sep := ”;
for Campo in ACampos.PKs do
begin
sql.Add(ACampos.Sep+ Campo + ‘= :’ + Campo);
ACampos.Sep := ‘ and ‘;
// setando os parâmetros
for PropRtti in ACampos.TipoRtti.GetProperties do
if CompareText(PropRtti.Name, Campo) = 0 then
begin
ConfiguraParametro(PropRtti, Campo, ATabela, Dados, True);
end;
end;
Open;
Result := RecordCount;
if Result > 0 then
begin
for PropRtti in ACampos.TipoRtti.GetProperties do
begin
Campo := PropRtti.Name;
SetaDadosTabela(PropRtti, Campo, ATabela, Dados);
ACampos.Sep := ‘,’;
end;
end;
end;
end;
//reflection da tabela e abertura da query preparada acima.
Result := ReflexaoSQL(ATabela, Comando);
finally
Dados.Free;
end;
end;
[/sourcecode]
Adicione esta unit ao projeto.
Pronto! Agora veremos como iremos utilizar esta unidade.
Digamos que depois de um certo tempo de uso, resolvemos adotar o IBX para acesso ao banco de dados. Eu mesmo já passei por isso no passado e digo que não foi uma tarefa muito agradável e nem tão pouco simples de ser feita. Para falar a verdade, passei algumas madrugadas em branco trocando componentes e fazendo ajustes para possibilitar o acesso ao banco. Agora, com este projeto, vou mostrar que de forma muito rápida, apenas trocando a classe, já estarei acessando o novo set de componentes.
Abra o datamodule dmPrin.
Vamos trocar TDaoUib por TDaoIbx. Lembre-se de adicionar ao uses a unit DaoIbx. Segue código do datamodule:
[sourcecode language=”delphi”]
unit udmPrin;
interface
uses
System.SysUtils, System.Classes, uib, Base, DaoUib, DaoIBX;
type
TdmPrin = class(TDataModule)
procedure DataModuleCreate(Sender: TObject);
procedure DataModuleDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Conexao: IDaoBase;
Dao: TDaoGenerico<TDaoIbx>;
end;
var
dmPrin: TdmPrin;
implementation
{%CLASSGROUP ‘System.Classes.TPersistent’}
{$R *.dfm}
procedure TdmPrin.DataModuleCreate(Sender: TObject);
begin
// configuração da conexão – utilizando DaoUib
// Conexao := TDaoUib.Create(‘C:\Users\Luiz\Documents\RAD Studio\Projects\Persistencia\Bd\BANCOTESTE.FDB’);
// configuração da conexão – utilizando IBX
Conexao := TDaoIbx.Create(‘C:\Users\Luiz\Documents\RAD Studio\Projects\Persistencia\Bd\BANCOTESTE.FDB’);
// dao genérico
Dao := TDaoGenerico<TDaoIbx>.Create;
Dao.Con := TDaoIbx(Conexao);
end;
procedure TdmPrin.DataModuleDestroy(Sender: TObject);
begin
Dao.Free;
end;
[/sourcecode]
Sobre o código, temos:
- Linha 17 – Dao é agora do tipo TDaoIbx;
- Linha 32 – comentei esta linha para deixar o registro de como era feito em UIB;
- Linha 35 – Instanciamos nossa conexão IBX.
E quanto ao formulário que executa os comandos CRUD, quais alterações deverão ser feitas? NENHUMA!
É isso mesmo, nenhuma alteração!
Basta executar e testar:
Foi reportado que há um erro quando se faz pesquisa na chave primária utilizando campos string. Veremos isso numa outra oportunidade.
Antes de encerrar, gostaria de falar um pouco sobre uma novidade que, ao meu ver, demonstra uma mudança nos rumos da Embarcadero no que tange ao acesso a dados no Delphi. Como todos já devem saber, a Embarcadero lançou recentemente o FireDac, um novo conjunto de acesso a dados (ou seria velho?!? AnyDac ressurge!) com ampla variedade de recursos, como por exemplo, acesso nativo a diversos bancos de dados com alto desempenho. Eu andei analisando e me pareceu muito interessante. Aí surgem os questionamentos:
- Mas essa já não era uma promessa do DbExpress?
- Então, com o FireDac ainda temos a necessidade de criar um ORM? Quem já assistiu aos vídeos que estão rolando na net sabe o por quê desta pergunta.
E aí pessoal, quais são suas impressões a respeito?
Código fonte:
Abraços.
Parabéns pela aula esta me ajudando muito.
Gostaria que se possível criasse um TDaoDBX (DBExpress) como seria.
Obrigado pela Atenção;
Ok, eu não tinha a intenção de implementar Dbx, mas vou colocar na programação.
Mas antes, ainda é necessário lapidar as classes já criadas, comparando as duas e retirando o que for desnecessário, tipo Tony Stark no Homem de Ferro 1.
Obrigado pela visita.
Muito legal saber que você ainda vai continuar esse projeto.
Esse projeto é muito interessante e voltarei a acompanhar os posts, pois assim como nos posts anteriores tenho certeza que tenho muito a aprender com essas técnicas que você utiliza.
Parabéns pelo belo trabalho.
link quebrado, poder arrumar mesmo agradeço.
Ok, corrigido.