Row Changed between retrieve and update

​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.

The following two tabs change content below.
Arquiteto de Software e Desenvolvedor Backend (quase Fullstack), geralmente trabalho com C#, PowerShell, Python, Golang, bash e Unity (esse é mais por hobby). Estou sempre buscando algo novo para aprender, adicionando novas ferramentas ao meu cinto de utilidades.
Posted in Dev, PowerBuilder and tagged , , , , , , , , , , , .