Row Changed between retrieve and update

Row Changed between retrieve and update

Overview

Enfrentando erros frustrantes no PowerBuilder? Neste post, mergulhamos no problema comum ‘Row Changed between retrieve and update’, explorando suas causas fundamentais e como superá-las. Desde a adequação de ‘Where Clause’ até o manejo de triggers e flags de status, oferecemos insights para um controle mais eficiente de registros. Ideal para desenvolvedores buscando soluções precisas e planejamento cuidadoso para evitar problemas futuros. Junte-se a nós para desvendar estes mistérios técnicos com uma abordagem prática e direta.

​Esta é uma mensagem comum e potencialmente frustrante onde supomos que o registro lógico da DataWindow está bloqueado por estar sendo usado em outro local. No PowerBuilder o registro que ele possui está diferente do que está na base. A ideia é que, quando outro usuário atualiza um registro que você já recuperou, você não vai ter a possibilidade de atualizar o mesmo registro sem recupera-lo novamente.

A opção “Where Clause” na “Update Properties” da DataWindow define o grau de bloqueio lógico implementado. Mudar esta propriedade pode fazer o sintoma desaparecer, mudando o controle da DataWindow para um nível mais “liberal” de bloqueio de registro lógico.

Esta pode ser uma solução rápida, mas que pode mascarar o verdadeiro problema: Um erro de lógica que pode trazer outros problemas no futuro. Uma mudança no nível de bloqueio de registro lógico deve ser feito com um planejamento cuidadoso, considerando o impacto da mudança em todo o sistema.

A causa básica desta mensagem é:

  1. A DataWindow gerou uma instrução UPDATE;
  2. A cláusula WHERE gerada para a instrução UPDATE não corresponde quaisquer registros no banco de dados;
  3. A cláusula WHERE é baseada na opção selecionada na caixa de diálogo “Update Properties” e sobre os valores que o DataWindow acredita estão no banco de dados;

Concorrência

A primeira coisa a examinar quando você receber essa mensagem é para garantir que ele realmente não refletem uma questão de concorrência. Coisas para verificar se há conflitos de simultaneidade incluem:

  • Outros usuários atualizando as informações na base;
  • Outras aplicações batch atualizando informações na base;
  • Outras janelas ou processos na mesma instância de sua aplicação: Isto pode ocorrer se você estiver exibindo as mesmas linhas em mais de uma DataWindow (não compartilhada) e então tenta atualizar as duas.

Triggers

Trigger de update e insert que afetem as colunas usadas na cláusula WHERE irão causar este problema. Se uma DataWindow gera um INSERT ou um UPDATE, a DataWindow vai continuar “achando” que os valores dela são os últimos enviados para o banco de dados. A próxima vez que DataWindow gera uma instrução UPDATE para modificar esse registro, ele irá usar esses valores na cláusula WHERE. Se um trigger modificou esses valores, a cláusula WHERE não irá coincidir com o registro.

Existe outra situação onde triggers podem causar este problema. Imagine o seguinte cenário:

  1. Update na tabela afetando uma linha;
  2. Existe um trigger de update na tabela.
  3. Dentro do trigger tenta-se atualizar uma tabela e 0 linhas são encontradas;
  4. O objeto SQLCA acusará 0 linhas afetadas pela datawindow;
  5. ERRO: Row Changed between retrieve and update

Neste caso, coloque “SET NOCOUNT ON” nos triggers para SQL Server para resolver problema.

Flags de Status

Esta é a causa mais comum desta mensagem. Se um valor na DataWindow é alterado e o estado é mudado para NotModified através de funções PowerScript, então o novo valor que vai ser utilizado como valor inicial da linha na cláusula WHERE. Outras considerações devem ser dadas a manipulação programática dos flags de status, e o efeito que eles têm sobre o SQL que o DataWindow gera.

O problema mais comum acontece quando os desenvolvedores tentam manipular os flags de status tentando imitar o que o atributo “Initial Values” de uma coluna faz nativamente. Quando valores iniciais sobre uma ou mais colunas são definidos, e uma linha é inserida no DataWindow, esses valores são definidos nas colunas da DataWindow, mas seus flags de status permanecem como NotModified! até que a primeira coluna é mudada.

Nesse ponto, todas as colunas com valores definidos inicialmente são alterados para Modified! de modo que eles são incluídos nas instruções SQL geradas. Usando isso, definir o “Initial Values” no design ou tempo de execução, você pode configurar valores padrão para colunas que, por si, não vão desencadear a geração de uma instrução SQL no Update(), mas serão incluídas se o usuário modifica um campo de modo que o resto da linha requer um INSERT.

Além de simplicidade, esta abordagem tem uma vantagem sobre a manipulação do flag de não influenciar o buffer de valores original, que muitos desenvolvedores farão inadvertidamente.