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 é:
- A DataWindow gerou uma instrução UPDATE;
- A cláusula WHERE gerada para a instrução UPDATE não corresponde quaisquer registros no banco de dados;
- 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:
- Update na tabela afetando uma linha;
- Existe um trigger de update na tabela.
- Dentro do trigger tenta-se atualizar uma tabela e 0 linhas são encontradas;
- O objeto SQLCA acusará 0 linhas afetadas pela datawindow;
- 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.