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:
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;
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:
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;
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.