Ir para conteúdo
  • Cadastre-se

dev botao

ID ainda nulo no Master/Detail


bnobre
  • Este tópico foi criado há 1616 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

  • Membros Pro

Olá a todos,

Utilizo Delphi 2010 + Zeos para conexão com MySQL no seguinte esquema de Banco de dados:

//Tabela de Declarações de Importação
tbl_nfe_itens_di:
id_nfe_itens_di - [integer, not null, auto_increment, pk],
ndi [varchar(12)],
ddi [date]

//Tabela de Adições de Declarações de Importação
tbl_nfe_itens_di_adi:
id_nfe_itens_di_adi - [integer, not null, auto_increment, pk],
id_nfe_itens_di - [integer, not null, fk],
nadi [integer]


No Delphi, utilizo a propriedade MasterSource do componente para tbl_nfe_itens_di_adi do tipo TZQuery para ligá-lo à tbl_nfe_itens_di, funciona perfeitamente para TUDO, exceto quando se dá o seguinte quadro: preciso inserir uma Adição quando a Declaração de Importação ainda não tem um ID (tbl_nfe_itens_di está com um registro novo também, portanto ID ainda está nulo), o campo tbl_nfe_itens_di_adi.id_nfe_itens_di é preenchido com 0. Quando dou o POST na tabela tbl_nfe_itens_di, ele primeiro dá POST nos datasets DETALHES (no caso, tbl_nfe_itens_di_adi), gerando uma exceção do banco de dados, porque a Adição está tentando ser salva antes da Declaração de Importação, com o campo que identifica a Declaração de Importação(id_nfe_itens_di) nulo.

 

Como os amigos contornam isso?

Desde já agradeço a atenção de todos

Link para o comentário
Compartilhar em outros sites

  • Consultores

Tente verificar se não há uma configuração no componente para alterar esse comportamento.

Caso contrário, uma alternativa seria você forçar o Post na tabela master antes de fazer a inserção da tabela detalhe.

  • Curtir 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

  • Membros Pro
17 minutos atrás, EMBarbosa disse:

Tente verificar se não há uma configuração no componente para alterar esse comportamento.

Caso contrário, uma alternativa seria você forçar o Post na tabela master antes de fazer a inserção da tabela detalhe.

Olá EMBarbosa, tudo bom meu amigo?

Vamos lá, infelizmente mesmo se existir essa mudança de comportamento no componente irá surgir um problema MUITO maior, que também me impede de forçar o post na tabela master antes, vou explicar com maior riqueza de detalhes o que ocorre, pois com certeza alguém já passou por isso e poderá compartilhar a solução:

Eu possuo um emissor de NFe e o preenchimento dos campos principais referentes a tela principal ficam na TBL_NFE, tais como serie, nnf, emitente, demi, etc.

Porém é óbvio que precisaria de outras tabelas se relacionando com a TBL_NFE, tais como TBL_NFE_ITENS(onde ficam detalhes dos produtos da nota), TBL_NFE_REFERENCIADAS (onde armazeno os detalhes de notas referenciadas a essa NFe), dentre outras, cada uma com sua própria tela de preenchimento de campos que é chamada pela tela principal do emissor.

Vou simular a utilização do sistema:

1° - O usuário na tela principal clica em incluir, a TBL_NFE fica em modo Insert e o mesmo começa a preencher os dados da referida tela/tabela, tais como série, número da nota, emitente, etc. Observe que não houve até então um Post através do botão CONFIRMAR da tela, portanto o PK dessa tabela (id_nfe) está 0, pois é um campo AutoIncrement do MySQL.

2° - O usuário através da tela principal chama a subtela para preenchimento dos produtos que alimentarão a TBL_NFE_ITENS que está associada a TBL_NFE através da FK id_nfe presente em ambas. Como ainda não sei se o usuário vai CONFIRMAR ou irá cancelar a inserção dessa NFe, abro a TBL_NFE_ITENS em CachedUpdates = True para armazenar os dados em memória e só Commitar se o botão CONFIRMAR na tela principal for clicado. Aqui já tem uma situação "atípica" pois observe que carrego a TBL_NFE_ITENS com a FK tendo valor 0, pois é o valor da PK da TBL_NFE no momento, como não existe nenhuma NFe com essa ID = 0 ele exibe corretamente só os itens que estou cadastrando na hora, mas na hora de clicar no botão CONFIRMAR da tela principal preciso gravar primeiro (conforme você sugeriu) a TBL_NFE, descobrir o valor gerado na PK da mesma (pois é AutoIncrement) e alimentar os itens da TBL_NFE_ITENS com esse valor correto (pois até o momento não esqueça que está 0). Faço isso com todas as telas/tabelas vinculadas a TBL_NFE que preciso há anos e deu certo até o momento. Só que agora...

3º - Agora tenho a TBL_NFE_ITENS_DI que tem a sua própria tela para preenchimento de seus campos assim como as tabelas vinculadas a TBL_NFE, só que ela é DIFERENTE pois é vinculada a TBL_NFE_ITENS que por sua vez é vinculada a TBL_NFE. Se eu usar a metodologia descrita na segunda parte irei ter problemas, pois vamos supor que eu queira ver as DIs do PRODUTO1, vou clicar em Editar o PRODUTO1 na tela principal, irá me abrir a tela de preenchimento desse produto que possui como PK (id_nfe_itens) o valor 0 (pois TAMBÉM está em Insert) da TBL_NFE_ITENS, depois vou clicar em DIs que vai me abrir a tela de preenchimento das DIs desse produto da TBL_NFE_ITENS_DI com a FK (id_nfe_itens) = 0, após preencher todos as DIs irei fechar a tela de DI, depois fechar a tela de produtos e voltar a tela principal de emissão da NFe. Aí ao tentar abrir a tela de preenchimento de outro produto, depois a tela de DIs desse outro produto irá aparecer todas as DIs do primeiro, pois todos os produtos no momento estão com a PK (id_nfe_itens) = 0. E como pode constatar eu não posso simplesmente gravar a tabela PAI antes, pois quero possibilitar ao meu cliente a possibilidade de CANCELAR toda a inserção. E isso ainda piora com a outra subtela de "Adições de DI", que é uma subtela da DI, que por sua vez é de Itens que é da tela principal.

Espero que eu tenha conseguido passar todo o cenário, pois é meio complexo. Eu nunca precisei ter mais de uma subtela/subtabela, então o procedimento realizado no segundo passo sempre funcionou comigo durante anos, mas agora que precisei acrescentar essa parte de DIs em meu emissor fui gerar essa nova hierarquia de subtela e me deparei com essa problemática. Como vocês agem nesse caso?

 

Link para o comentário
Compartilhar em outros sites

  • Consultores
3 horas atrás, doidopb disse:

Espero que eu tenha conseguido passar todo o cenário, pois é meio complexo.

Me parece que eu entendi sua situação.

3 horas atrás, doidopb disse:

Eu nunca precisei ter mais de uma subtela/subtabela, então o procedimento realizado no segundo passo sempre funcionou comigo durante anos, mas agora que precisei acrescentar essa parte de DIs em meu emissor fui gerar essa nova hierarquia de subtela e me deparei com essa problemática. Como vocês agem nesse caso?

A solução que vejo é você remover o campo auto-incremento do banco de dados e passar a fazer o tratamento na sua aplicação, trabalhando com tudo na memória para apenas na confirmação enviar ao banco de dados. É assim que eu já fiz.

Na verdade, a melhor maneira de trabalhar com a possibilidade do usuário cancelar o trabalho é fazer tudo apenas na memória e só então jogar no BD.

Isso fica mais fácil de implementar quando você separa as responsabilidades. Uma maneira é usando classes específicas (sem usar componentes DB-Aware como DBEdit, DBLookup, DBMemo e similares). Outra possibilidade é usar uma tabela que funcione como memória como o TClientDataset antes de enviar ao BD.

Outra coisa que você pode considerar é salvar o trabalho do usuário no BD mesmo com uma flag mostrando que o ainda não foi confirmado. Muito que é feito na Web hoje em dia é assim. Como exemplo Google Docs salva tudo que você está digitando mesmo sem pedir...

  • Curtir 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

  • Membros Pro
1 hora atrás, EMBarbosa disse:

Me parece que eu entendi sua situação.

A solução que vejo é você remover o campo auto-incremento do banco de dados e passar a fazer o tratamento na sua aplicação, trabalhando com tudo na memória para apenas na confirmação enviar ao banco de dados. É assim que eu já fiz.

Na verdade, a melhor maneira de trabalhar com a possibilidade do usuário cancelar o trabalho é fazer tudo apenas na memória e só então jogar no BD.

Isso fica mais fácil de implementar quando você separa as responsabilidades. Uma maneira é usando classes específicas (sem usar componentes DB-Aware como DBEdit, DBLookup, DBMemo e similares). Outra possibilidade é usar uma tabela que funcione como memória como o TClientDataset antes de enviar ao BD.

Outra coisa que você pode considerar é salvar o trabalho do usuário no BD mesmo com uma flag mostrando que o ainda não foi confirmado. Muito que é feito na Web hoje em dia é assim. Como exemplo Google Docs salva tudo que você está digitando mesmo sem pedir...

Boas dicas...

Você disse já ter feito algo similar jogando tudo na memória e enviando ao fim no banco, o problema é que depois de confirmado o cadastro da NFe o usuário AINDA pode modificar ela posteriormente, tornando mais complexo o tratamento, pois ele poderia adicionar/editar/excluir DIs posteriormente, mas creio que a saída está nas suas sugestões.

Ainda tem parte desse código que usou ou algum exemplo para eu me basear?

Desde já agradeço a ajuda

Link para o comentário
Compartilhar em outros sites

  • Consultores
11 minutos atrás, doidopb disse:

o problema é que depois de confirmado o cadastro da NFe o usuário AINDA pode modificar ela posteriormente, tornando mais complexo o tratamento, pois ele poderia adicionar/editar/excluir DIs posteriormente,

Não fica mais complexo porque o tratamento é basicamente o mesmo: carrega na memória e depois envia ao BD só quando o usuário confirmar.

15 minutos atrás, doidopb disse:

Ainda tem parte desse código que usou ou algum exemplo para eu me basear?

Não tenho... Mas não deve ser muito difícil achar alguma coisa com o TClientDataSet.

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

  • Membros Pro
16 minutos atrás, EMBarbosa disse:

Não fica mais complexo porque o tratamento é basicamente o mesmo: carrega na memória e depois envia ao BD só quando o usuário confirmar.

Não tenho... Mas não deve ser muito difícil achar alguma coisa com o TClientDataSet.

A grande complexidade que eu vejo é  associar corretamente os registros das subtelas às telas antes de enviar tudo ao banco, pois mesmo em memória se eu não especificar um ID relacionando eles não irá ocorrer a separação, ex: Adição 1 da D1 do Item1, Adição 2 da DI2 do Item2...

Ao meu ver terei que criar valores de IDs temporários para que essa associação entre as telas aconteça, com isso as Adições serão associadas às DIs que serão associadas aos Itens da NFe corretamente. Aí na hora de confirmar jogo tudo no banco substituindo os IDs pelo valores gerados pelo mesmo... Estou certo?

Link para o comentário
Compartilhar em outros sites

  • Consultores
1 minuto atrás, doidopb disse:

Ao meu ver terei que criar valores de IDs temporários para que essa associação entre as telas aconteça, com isso as Adições serão associadas às DIs que serão associadas aos Itens da NFe corretamente. Aí na hora de confirmar jogo tudo no banco substituindo os IDs pelo valores gerados pelo mesmo... Estou certo?

Dependendo da implementação, sim. É isso que eu quis dizer com "você remover o auto-incremento".

Mas tem uma outra saída que mencionei: Reescrever usando classes ou um ORM. Porque daí uma DI vai ficar associada ao Item usando classes, tendo ou não uma ID.

Só que isso dá muito trabalho pra fazer no sistema inteiro. Se estiver com prazo apertado, pode ser bem difícil de conseguir.

Mas é algo a se pensar quando for fazer novas telas.

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

  • Membros Pro

Rapaz, entao vai demorar mesmo pois eu também não sei trabalhar com classes e nem sei o que é ORM.

Vou tentar criar esses valores de ID temporariamente com inteiro negativos (pois evito conflitos com os IDs em uso que são positivos) e depois associar aos mesmos os valores corretos gerados pelo banco ao CONFIRMAR.

Link para o comentário
Compartilhar em outros sites

  • Este tópico foi criado há 1616 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.