Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

lucascolferai

[Resolvido] Novo valor do campo indisponível depois do post

Recommended Posts

Olá pessoal,

 

Não achei nada no fórum, então estou criando esse tópico novo.

 

Tenho o seguinte cenário:

- Aplicação em Delphi 7

- BD Firebird 1.5

- Componentes de acesso da aba Interbase (do próprio Delphi 7)

- Estou criando um cadastro de fornecedores

- Tabela de fornecedores com campo-chave autoincremental (feito por um Generator e por uma Trigger)

 

BOTÃO INCLUIR

  dm.ibtFornecedores.insert;
  dm.ibtFornecedoresFORDATACADASTRO.AsString    := datadosistema;
  dm.ibtFornecedoresFORDATAATUALIZACAO.AsString := datadosistema;
  dm.ibtFornecedoresFORSTATUS.AsString := 'A';

BOTÃO GRAVAR

  // Operações
  try
    if not dm.itrTransa.InTransaction then
      dm.itrTransa.StartTransaction;

    dm.ibtFornecedores.post;

    // LOG
    codigo := dm.ibtFornecedoresFORCODIGO.Value;
    insereLog ('Inclusão do fornecedor nº '+inttostr(codigo));

    dm.itrTransa.CommitRetaining;
  except
    MessageDlg('ATENÇÃO!!! Ocorreu um erro na operação.'+#13+
               'Comunique imediatamente o suporte técnico.'+#13#13+
               'Será gravado um arquivo de log contendo maiores informações.',mtError,[mbOK],0);
    CriarLogErro(datadosistema, horadosistema, sExceptionAcao, 'Tentou incluir o fornecedor nº '+inttostr(codigo));
    dm.itrTransa.Rollback;
  end;

Acontece que, no Botão GRAVAR, na linha onde a variável 'codigo' recebe o FORCODIGO, dm.ibtFornecedoresFORCODIGO.Value chega como 0 (zero). Ou seja, não consigo pegar o valor de FORCODIGO que foi gerado automaticamente para usa-lo no meu sistema de Log. Olhei no IBExpert e a Trigger e o Generator estão funcionando certinhos, o campo FORCODIGO recebe o valor de maneira correta se eu incluo um registro pelo IBExpert.

 

Na minha TIBTable, tenho todos os campos adicionados. No campo referente ao FORCODIGO, as propriedades são Required = false, AutoGenerateValue = arNone (já tentei com arAutoInc), ProviderFlags = [pfInUpdate,pfInWhere] (já tentei com [pfInWhere]).

 

Percebi, também, uma coisa. Quando navego com os comandos First, Prior, Next e Last, percebo que o novo registro que inclui aparece na segunda posição (pois usei o Insert) e TAMBÉM na última posição!!! Depurando, detectei que a primeira cópia do registro tem FORCODIGO = 0 e a segunda cópia tem o FORCODIGO correto. Troquei o Insert por Append e aparece apenas uma cópia do registro, mas com FORCODIGO = 0.

 

Testes que eu fiz: forcei um commit (com o Evaluate/Modify, CTRL+F7) mas não fez nada. Forcei um Refresh na tabela e aí deu certo, mas o ponteiro volta pro primeiro registro. E mesmo assim, não consigo pegar o código do registro inserido, pra usar no Log.

 

E aí, alguém pode me dar uma luz? :(

 

Olá pessoal,

 

Identifiquei que se trata de um problema conhecido no Firebird e em outros bancos. O SGBD não retorna nada para a aplicação depois do Post, com isso só consigo recuperar o ID através de um Refresh e um Last na IBTable. Mas isso é gambiarra e pode gerar erros, por exemplo, quando muitos usuários estiverem usando o sistema e mais de um registro for incluído simultâneamente. No intervalo de tempo, 2 registro poderiam ser gravados e um mesmo "ULTIMO_ID" poderia ser informado para os 2 usuários que fizeram a gravação. Pra mim seria um problema, pois furaria meu sistema de Log.

 

No SQL Server, eu resolveria com um "SELECT @@IDENTITY". Já com o MySQL, eu resolveria com um "SELECT LAST_INSERT_ID()". Para ambos, o "ULTIMO_ID" seria retornado por conexão, impedindo o problema de concorrência. Mas não tô achando nada desse tipo para Firebird. Alguém conhece algo assim?

 

Uma alternativa menos "improvisada" seria forçar o GENERATOR a fornecer o novo ID e atribuí-lo diretamente ao campo, antes do post. Mas vocês devem concordar comigo que isso não é o ideal, né? Senão, pra que serviria a TRIGGER? Praticamente não seria mais usada.

 

E aí, alguém pode me ajudar?

 

:)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá pessoal,

 

Percebi que muitos leram o tópico mas não houve nenhuma resposta. Concluo que não haja uma solução ideal para esse problema. Apenas para não deixar o tópico sem conclusão, deixo aqui para os que forem lê-lo outro dia, a solução que adotei.

 

Resolvi "forçar" o GENERATOR a fornecer o novo ID e atribui-lo ao campo, via código, antes do post. O código ficou assim:

 

  // OPERAÇÕES
  try
    if not dm.itrTransa.InTransaction then
      dm.itrTransa.StartTransaction;

    // Obter o FORCODIGO
    dm.ibqSql.SQL.Text :=
      'SELECT GEN_ID (GEN_FORNECEDORES_FORCODIGO, 1) AS FORCODIGO FROM RDB$DATABASE ';
    dm.ibqSql.Open;
    codigo := dm.ibqSql.FieldByName('FORCODIGO').AsInteger;
    dm.ibqSql.Close;

    // Gravar
    dm.ibtFornecedoresFORCODIGO.AsInteger := codigo;
    dm.ibtFornecedores.post;

    // LOG
    insereLog ('Inclusão do fornecedor nº '+inttostr(codigo));

    dm.itrTransa.CommitRetaining;
  except
    MessageDlg('ATENÇÃO!!! Ocorreu um erro na operação.'+#13+
               'Comunique imediatamente o suporte técnico.'+#13#13+
               'Será gravado um arquivo de log contendo maiores informações.',mtError,[mbOK],0);
    CriarLogErro(datadosistema, horadosistema, sExceptionAcao, 'Tentou incluir o fornecedor nº '+inttostr(codigo));
    dm.itrTransa.Rollback;
  end;

Obrigado a todos que leram o tópico e tentaram ajudar.

 

:)

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.