Fórum M/D (3 níveis em cascata) com Firedac + CacheUpdate #617972
26/04/2022
0
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):
1 2 3 4 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /// 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
Curtir tópico
+ 0Posts
27/04/2022
Emerson Nascimento
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).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /// 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
27/04/2022
Júlio Ferreira
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
27/04/2022
Júlio Ferreira
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /// 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
27/04/2022
Júlio Ferreira
O mestre é o ds e não dsTabela.
1 | TUtil . Dados . prepararConsultaDetalhes( classe, ds, '' id '' , '' idTabela '' ); |
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)