M/D (3 níveis em cascata) com Firedac + CacheUpdate
Pessoal, bom dia!
Sobre as configurações do M/D com o FireDAC, acredito que tudo seja bastante simples e intuitivo. No meu caso, utilizo o PostgreSQL e tudo aparentemente roda com perfeição.
Recentemente, tive a necessidade de fazer um M/D em três níveis: mestre->detalhe->detalhe->detalhe. O comportamento é bem estranho e parece que estou deixando alguma coisa passar, pois não estão funcionando os recursos de propagar nos detalhes e ao alterar um mestre (seja o principal ou um dos detalhes mestres), o seu detalhe imediato perde dados.
Abaixo, o exemplo dos dois métodos usados para configurar o M/D dos datasets e mais abaixo, as consultas realizadas e configuradas (todas com as FKs devidamente definidas).
O esquema é um cadastro de tabelas salariais com a seguinte estrutura (em PostgreSQL):
Métodos para configuração:
Consultas:
Agradeço antecipadamente qualquer dica ou sugestão, bem como indicar algum possível erro na estrutura.
Sobre as configurações do M/D com o FireDAC, acredito que tudo seja bastante simples e intuitivo. No meu caso, utilizo o PostgreSQL e tudo aparentemente roda com perfeição.
Recentemente, tive a necessidade de fazer um M/D em três níveis: mestre->detalhe->detalhe->detalhe. O comportamento é bem estranho e parece que estou deixando alguma coisa passar, pois não estão funcionando os recursos de propagar nos detalhes e ao alterar um mestre (seja o principal ou um dos detalhes mestres), o seu detalhe imediato perde dados.
Abaixo, o exemplo dos dois métodos usados para configurar o M/D dos datasets e mais abaixo, as consultas realizadas e configuradas (todas com as FKs devidamente definidas).
O esquema é um cadastro de tabelas salariais com a seguinte estrutura (em PostgreSQL):
Master -> tabelas_salariais [ id pk ] Detalhe 1 -> tabelas_salariais_classes [ id pk, idTabela fk->tabelas_salariais(id) ] Detalhe 2 -> tabelas_salariais_niveis [ id pk, idClasse fk->tabelas_salariais_classes(id) ] Detalhe 3 -> tabelas_salariais_valores [ id pk, idNivel fk->tabelas_salariais_niveis(id) ]
Métodos para configuração:
class procedure TUtil.Dados.prepararConsultaMestre(mestre: TFDRdbmsDataSet); begin mestre.CachedUpdates := true; mestre.SchemaAdapter := TFDSchemaAdapter.Create( mestre ); mestre.UpdateOptions.CheckRequired := false; end; class procedure TUtil.Dados.prepararConsultaDetalhes(detalhes: TFDRdbmsDataSet; dsMestre: TDataSource; campoMestre, camposIndice: string); begin detalhes.MasterSource := dsMestre; detalhes.MasterFields := campoMestre; detalhes.IndexFieldNames := camposIndice; detalhes.CachedUpdates := true; detalhes.SchemaAdapter := TFDSchemaAdapter( TFDRdbmsDataSet( dsMestre.DataSet ).SchemaAdapter ); detalhes.FetchOptions.DetailCascade := true; detalhes.UpdateOptions.CheckRequired := false; end;
Consultas:
/// Tabela salarial tabela := TFDQuery.Create( Self ); tabela.SQL.Add( ''select * from tabelas_salariais where id = :id'' ); tabela.par( id ); <- o método par já faz a configuração para o parâmetro TUtil.Dados.prepararConsultaMestre( tabela ); tabela.Open; /// Classes de tabelas classe := TFDQuery.Create( Self ); classe.SQL.add( ''select * from tabelas_salariais_classes where idTabela = :id order by codigo'' ); classe.par( id ); <- o método par já faz a configuração para o parâmetro TUtil.Dados.prepararConsultaDetalhes( classe, ds, ''id'', ''idTabela'' ); classe.Open; /// Níveis salariais nivel := TFDQuery.Create( Self ); nivel.SQL.Add( ''select * from tabelas_salariais_niveis where idClasse = :id order by codigo'' ); nivel.ParamByName( ''id'' ).DataType := ftInteger; TUtil.Dados.prepararConsultaDetalhes( nivel, dsClasse, ''id'', ''idClasse'' ); nivel.Open; /// Valores salariais valor := TFDQuery.Create( Self ); valor.SQL.Add( ''select * from tabelas_salariais_valores where idNivel = :id order by iniValidade desc'' ); valor.ParamByName( ''id'' ).DataType := ftInteger; TUtil.Dados.prepararConsultaDetalhes( valor, dsNivel, ''id'', ''idNivel'' ); valor.Open;
Agradeço antecipadamente qualquer dica ou sugestão, bem como indicar algum possível erro na estrutura.
Júlio Ferreira
Curtidas 0
Respostas
Emerson Nascimento
26/04/2022
os datasources estão conectados aos datasets?
no trecho das consultas você está criando os objetos em tempo de execução. em que momento está sendo feita a ligação do dataset com o datasource?
nomeie os datasource de modo que possamos identificar a relação com o dataset (dsClasse, dsNivel).
no trecho das consultas você está criando os objetos em tempo de execução. em que momento está sendo feita a ligação do dataset com o datasource?
nomeie os datasource de modo que possamos identificar a relação com o dataset (dsClasse, dsNivel).
/// Tabela salarial tabela := TFDQuery.Create( Self ); tabela.SQL.Add( ''select * from tabelas_salariais where id = :id'' ); tabela.par( id ); <- o método par já faz a configuração para o parâmetro TUtil.Dados.prepararConsultaMestre( tabela ); dsTabela.dataset := tabela; // faz a ligação com o datasource tabela.Open; /// Classes de tabelas classe := TFDQuery.Create( Self ); classe.SQL.add( ''select * from tabelas_salariais_classes where idTabela = :id order by codigo'' ); classe.par( id ); <- o método par já faz a configuração para o parâmetro TUtil.Dados.prepararConsultaDetalhes( classe, dsTabela, ''id'', ''idTabela'' ); dsClasse.dataset := classe; // faz a ligação com o datasource classe.Open; /// Níveis salariais nivel := TFDQuery.Create( Self ); nivel.SQL.Add( ''select * from tabelas_salariais_niveis where idClasse = :id order by codigo'' ); nivel.ParamByName( ''id'' ).DataType := ftInteger; TUtil.Dados.prepararConsultaDetalhes( nivel, dsClasse, ''id'', ''idClasse'' ); dsNivel.dataset := nivel; // faz a ligação com o datasource nivel.Open; /// Valores salariais valor := TFDQuery.Create( Self ); valor.SQL.Add( ''select * from tabelas_salariais_valores where idNivel = :id order by iniValidade desc'' ); valor.ParamByName( ''id'' ).DataType := ftInteger; TUtil.Dados.prepararConsultaDetalhes( valor, dsNivel, ''id'', ''idNivel'' ); dsValor.dataset := valor; // faz a ligação com o datasource valor.Open;
GOSTEI 0
Júlio Ferreira
26/04/2022
os datasources estão conectados aos datasets?
no trecho das consultas você está criando os objetos em tempo de execução. em que momento está sendo feita a ligação do dataset com o datasource?
nomeie os datasource de modo que possamos identificar a relação com o dataset (dsClasse, dsNivel).
no trecho das consultas você está criando os objetos em tempo de execução. em que momento está sendo feita a ligação do dataset com o datasource?
nomeie os datasource de modo que possamos identificar a relação com o dataset (dsClasse, dsNivel).
Olá Emerson, boa tarde!
Sim, os datasources estão definidos em modo de design. Na verdade, por uma falha minha na postagem, removi a linha que define a consulta aos seus respectivos datasources, mas considere isso como ok.
Obrigado.
GOSTEI 0
Júlio Ferreira
26/04/2022
A codificação correta seria essa, levando em consideração que os objetos TDataSource estão definidos em design.
/// Tabela salarial tabela := TFDQuery.Create( Self ); tabela.SQL.Add( ''select * from tabelas_salariais where id = :id'' ); tabela.par( id ); <- o método par já faz a configuração para o parâmetro TUtil.Dados.prepararConsultaMestre( tabela ); tabela.Open; ds.DataSet := tabela; /// Classes de tabelas classe := TFDQuery.Create( Self ); classe.SQL.add( ''select * from tabelas_salariais_classes where idTabela = :id order by codigo'' ); classe.par( id ); <- o método par já faz a configuração para o parâmetro TUtil.Dados.prepararConsultaDetalhes( classe, dsTabela, ''id'', ''idTabela'' ); classe.Open; dsClasse.DataSet := classe; /// Níveis salariais nivel := TFDQuery.Create( Self ); nivel.SQL.Add( ''select * from tabelas_salariais_niveis where idClasse = :id order by codigo'' ); nivel.ParamByName( ''id'' ).DataType := ftInteger; TUtil.Dados.prepararConsultaDetalhes( nivel, dsClasse, ''id'', ''idClasse'' ); nivel.Open; dsNivel.DataSet := nivel; /// Valores salariais valor := TFDQuery.Create( Self ); valor.SQL.Add( ''select * from tabelas_salariais_valores where idNivel = :id order by iniValidade desc'' ); valor.ParamByName( ''id'' ).DataType := ftInteger; TUtil.Dados.prepararConsultaDetalhes( valor, dsNivel, ''id'', ''idNivel'' ); valor.Open; dsValor.DataSet := valor;
GOSTEI 0
Júlio Ferreira
26/04/2022
Não consigo apagar e nem editar uma postagem, coloquei um trecho errado.
O mestre é o ds e não dsTabela.
O mestre é o ds e não dsTabela.
TUtil.Dados.prepararConsultaDetalhes( classe, ds, ''id'', ''idTabela'' );
GOSTEI 0