sexta-feira, abril 12, 2013

FireDAC - Cadastro Mestre/Detalhe


Veja nesse vídeo como criar um cadastro mestre/detalhe, que faz uso de um campo auto-incremento, utilizando o FireDAC.


32 comentários:

Cristiano Chiele disse...
Este comentário foi removido pelo autor.
Cristiano Chiele disse...
Este comentário foi removido pelo autor.
Isaque Pinheiro disse...

Gostaria de vê esse mesmo exemplo do video usando o evento OnUpdateRecord do TADQuery, pois já tentei de todas as formas usa-lo e não grava no banco de jeito algum.

Se não usar o evento OnUpdateRecord, funciona 100%

Poderia me enviar um exemplo usando esse evento ?

Alan Gomes disse...

Estou preparando um vídeo com os eventos onUpdateRecord e onUpdateError do componente TADQuery

Hugo Fabrício disse...

Estou com problemas no mestre detalhe usando FireBird,
quando uso o Adqry sem Cache funciona normal.

Mas quando habilito o Cache e coloco como no exemplo ele não salva na base e nem da erros
Estou com um exemplo se for o caso posso te enviar !

Alan Glei disse...

Boas notícias! Recebi um retorno da Embarcadero quanto ao problema do CacheUpdate nos bancos IB e FB. O update 1 do XE5 já vem com a correção do problema!

Nilton Oliveira disse...

Alan, quanto o auto incremento para master detail usando firedac, poderia nos passar um vídeo aula sobre o assunto.

Olimpio Gonzatto Jr. disse...

Olá Alan,

Testei o seu exemplo utilizando a versão xe5 update 2 e retorna o seguinte erro:

[FireDAC] [DatS]-16. Cannot process - no parent row. Constraint [ForeignKeyConstraint].

Saberia me dizer porque deste erro?

LuisP disse...


Mesmo erro do amigo "Olimpio Gonzatto Jr" Sempre usei o Zeos nunca tive problema, para compatibilizar minhas aplicações resolvi usar o bendito firedac que diziam ser top rapido e nativo. Segui o exemplo com sql server e da mesmo problema, não consigo resolver alguem tem a solução ?

[FireDAC] [DatS]-16. Cannot process - no parent row. Constraint [ForeignKeyConstraint].

Volmir Lauermann disse...

Boa tarde Alan...

Estou enfrentando este problema:

[FireDAC] [DatS]-16. Cannot process - no parent row. Constraint [ForeignKeyConstraint].

Segui religiosamente seus passo a passo no vídeo, exceto pelo detalhe de estar utilizando o banco firebird e o XE6...

Alguma ideia de qual seria o problema?

Alan Glei disse...

Fiz testes aqui com o Interbase e o Delphi XE6, tudo funcionou certinho... se possível me mandem esses códigos que estão gerando erro para que eu possa reproduzir aqui. Ok!

Alan Glei disse...

Consegui simular o erro "[FireDAC] [DatS]-16. Cannot process - no parent row. Constraint [ForeignKeyConstraint].". O que ocorre é o seguinte: vocês estão incluindo um registro filho sem antes salvar o registro mestre... segue um link para um vídeo explicando o problema com mais detalhes Ok!

https://dl.dropboxusercontent.com/u/90063499/Erro%20MestreDetalhe%20FireDAC.mp4

Sakamoto disse...

Bom dia Alan,

Estou trabalhando com o Firedac e Oracle. E fiquei em uma dúvida em relação ao TFDPhysOracleDriverLink e TFDGUIxWaitCursor.

Esses 2 componentes devem estar presentes em todos os TForm que acessam o Oracle? Se eu utilizar um TDataModule só preciso adicionar apenas um para o projeto todo?

Att,

Mytracelog - Registro de um DBA
http://mytracelog.blogspot.com

Mauro disse...

Funciona perfeitamente, mas como ficaria esse mesmo exemplo em um ambiente 3 camadas?

Rafael Campos disse...

Olá Alan
Estou usando o XE7 e mesmo assim estou com o dilema de não conseguir persistir no banco firebird. Habilitei a opção autoincremento na propriedade dos campos pôs o firebird não tem esse tipo de variável. Quando vou gravar não acontece erro nenhum, porém quando faço o refresh os dados somem.
Segue o trecho que uso para gravar

if not DTMTabelas.FDConnection.InTransaction then
DTMTabelas.FDConnection.StartTransaction;
try
DTMTabelas.FDConnection.ApplyUpdates([DTMTabelas.QryVenda,DTMTabelas.QryPAF,DTMTabelas.QryItemVenda,DTMTabelas.QryMovimento]);
DTMTabelas.FDConnection.Commit;
except
DTMTabelas.FDConnection.Rollback;
end

Felipe Garrido disse...
Este comentário foi removido pelo autor.
Felipe Garrido disse...

Parabéns pelo video, me ajudou muito.

Gostaria se possível de tirar uma dúvida, estou usando MSSQL e quando dou um post no mestre para inserir os detalhes tenho a exceção [FireDAC][DatS]-15. Duplicate row found on unique index. Constraint [_FD_UC_UniqueConstraint], só dá certo se o dataset mestre estiver vazio e eu inserir um registro, se ele está mostrando alguns registros já inseridos e vou inserir mais um, acontece o erro acima, será que é algum erro de índice ou provider flags?

Lucas Belo disse...

Rafael Campos, se você estiver utilizando o evento "OnUpdateRecord", você deve altera o valor do parâmetro "AAction" dessa forma: AAction := TFDErrorAction.eaDefault;

Por padrão ele vai como TFDErrorAction.eaApplied, entendendo que você vai fazer o post dos dados no banco, pra isso você pode usar o componente TFDUpdateSQL. Para utilizar esse componente eu te recomendo ler a documentação porquê ele tem alguns detalhes e facilitações.

Lucas Belo disse...
Este comentário foi removido pelo autor.
Lucas Belo disse...

Felipe Garrido, isso está acontecendo porque você adicionou um campo na propriedade "IndexFieldNames" e ele não aceita duplicações. O que você pode fazer é, no evento "OnNewRecord" você adicionar um valor incremental nesse campo index, ex: "MEU_CAMPO_INDEX" := DataSet.RecordCount + 1. Para gerar o valor real desse campo, o que será persistido no banco de dados, você deve utilizar o evento "OnUpdateRecord" e gerar o valor para esse campo em uma transação, assim:

if (ARequest in [TFDActionRequest.arInsert]) then
begin
DataSet.Edit();
DataSet.FieldByName('MEU_CAMPO_INDEXADO').AsInteger := GeraCampoInc('MEU_CAMPO_INDEXADO');
DataSet.Post();
end;
AAction := TFDErrorAction.eaDefault

Lucas Belo disse...

Sakamoto, basta declarar um único local, geralmente deixo junto à declaração da conexão com o banco.

Lucas Belo disse...

Mauro, utilizando um webservice Restfull, quando o objeto for serializado, ao invés do atributo "type", o framework vai passar o atributo "ref" que é a referência ao ponteiro do objeto, e assim, entre as requisições, você pode ir trabalhando com o dataset. Se você estiver utilizando Restless, o melhor é você não trabalhar com datasets em memória entre as pontas(cliente/servidor).

No servidor, ex: a tabela de estados pode estar em um dataset que você vai abrí-lo somente na primeira requisição e mantê-lo em uma variável global ou de classe(pode-se utilizar o padrão singleton), lembrando que deve-se tomar cuidado com o acesso concorrente(thread-safe).

Essa prática é melhor utilizada no lado cliente, onde você pode fazer várias alterações nos dados e depois enviar um batch contendo todas as alterações, podendo inclusive ser o "delta".

ale sorrilha disse...

Olá amigos! Primeiramente gostaria de agradecer a vc Alan pelos excelente post. Tenho uma dúvida. O exemplo funcionou certinho relacionando a tabela master com a detail. Mas tenho a necessidade de mais um relacionamento com a tabela detail e não com a master. Exemplo

MASTER-->DETAIL-->3º TABELA

Isso é possível utilizando cache?

Obrigado
Sorrilha

Alan Glei disse...

Mesmo procedimento, faça o relacionamento do seu novo dataset com o Detail e não esqueça de apontar o SchemeAdapter neste novo Dataset Ok!

ale sorrilha disse...

Obrigado pela resposta Alan. Mas o problema tá aí! Se ligar com o detail a chave primaria do master e detail (em modo de insert) estrarão -1 assim não deu certo. Na terceira tabela tenho:

id_master (-1)
id_detail (-1)
id_terceira_tabela (identy)

o relacionamento grava com -1
Obrigado mais uma vez.

Tiago Melo disse...

Alan, show de bola os posts, obrigado por compartilhar com a comunidade seu conhecimento.
Enfim estou passando pelo problema que já foi citado aqui: "Cannot process - no parent row. Constraint [ForeignKeyConstraint]", estou usando XE7 + SQL Server, eu reparei que no video que vc postou sobre esse assunto e realmente ocorre como vc mostrou ou seja caso não tenha dado post no mestre ocorre o erro acima, porém vc realiza o post no grid do mestre com seta pra cima e para baixo, no meu caso aqui o usuario do meu sistema não vai realizar esse procedimento de dar seta pra cima e para baixo...tentei fazer o post no mestre via codigo...QrMestre.Post e mesmo assim o erro persistiu, saberia me dizer como contornar essa situação?

Tiago Melo disse...

bom depois de bater cabeça,encontrei um post onde se fazia isso no botão "novo"
QrMestre.Append;
QrMestre.Post;
QrMestre.Edit;

na minha opnião não deveria ser isso, pois como se trata de nova inclusão não justifica o edit abaixo, pois dessa forma o estado do dataset passa a não mais ser de insert e sim de edit, o que dependendo da situação pode prejudicar a escrita do codigo, na minha opnião é BUG. Mas enfim funcionou e vou usar o MD no firedac pois vou poupar muitas horas de desenvolvimento com esse modelo.

Diego Maccari disse...

Boa tarde Alan, parabéns pelo post, esclareceu muito para mim, seria possível você demonstrar como realizar persistência mestre detalhe usando DataSnap/REST? tenho feito vários testes aqui e não estou conseguindo persistir os dados, desde já obrigado.

Jorge Mario Fonseca Pinto disse...

Bom dia Allan !! Primeiramente obrigado pelo conteúdo de valor e sua disposição em ensinar.
Segui todo o procedimento certinho e deu tudo certo, mas notei que funciona bem para inserts e edits, ou seja, novos registros e alterações de registros já existentes. Mas e a deleção? A deleção pode ser feita em cache também? Tentei aqui e não consegui... ou precisamos fazer a deleção diretamente nos datasets e trata-la separadamente? E se tiver que ser feita separadamente é necessário então fazer um Dataset.Delete em cada dataset ou apenas no mestre e o resto ocorre em cascata?

Unknown disse...

Bom dia Alan..... parabens pelo vídeo e tambem obrigado pela ajuda quer voce nos esta proporcionando. Uma duvida.... vcs saberia me dizer porque nao me aparece erro nenhum quando da inclusao no detalhe de chave duplicada?.... nao me da o erro de Key Violation?

jasoft disse...

Boa Tarde Alan.
Parabéns pelo post. Vi que você conseguiyu simular o erro "[FireDAC] [DatS]-16. Cannot process - no parent row. Constraint [ForeignKeyConstraint].". O que ocorre é o seguinte: vocês estão incluindo um registro filho sem antes salvar o registro mestre... segue um link para um vídeo explicando o problema com mais detalhes Ok!
Vi também o seu video em https://dl.dropboxusercontent.com/u/90063499/Erro%20MestreDetalhe%20FireDAC.mp4

Sei que o seu post é antigo, mas estou usando o XE8+Firedac+Firebird e também obtive o mesmo erro que foi obtido pelo outros colegas acima. Pergunto. Trata-se de um erro no FIREDAC e se o meesmo já foi corrigido pela Embarcadero? Se não, não entendi porque tenho que salvar o registro mestre antes (pois entendi que com CacheUpdate isso é feito em sequencia pelo comando AppplyUpdate do TADSchemaAdapter?

Adeildo Silva disse...

Olá pessoal,

No projeto de exemplo "SampleDataSnapFireDAC_Client.dpr" em "Object Pascal \ DataSnap \ FireDAC" que acompanha o Delphi 10 Seattle e outras versões anteriores, adicionei dois botões na unit "ClientUnit.pas". O primeiro botão faz uma inserção e o segundo exclusão de registros na query mtOrders, no entanto, no "Post Updates", é levantada uma uma exceção no lado do servidor: FireDAC [DatS] -16. Can not process - no parent. Restriction [ForeingnKeyConstraint]. Alguém já passou por esse problema para me ajudar a encontrar uma solução?

Código nos botões:
-------------------
procedure TClientForm.AddClick (Sender: TObject);
begin
DataModuleFDClient.mtOrders.Append;
end;

procedure TClientForm.DeleteClick (Sender: TObject);
begin
DataModuleFDClient.mtOrders.Delete;
end;
----

Muito obrigado,

Adeildo Silva