Atualizacao Simultanea de Tabelas FireBird x DbExpress....
05/01/2006
0
Imaginem loja com 4 PC´s, um no caixa, tres no balcao e um servidor.
Servidor dando entrada em Nota Fiscal, alterando Precos, etc...
Balcao vendendo, consultando, cadastrando cliente, alterando cadastro produtos, etc...
Pdv no caixa, concluindo vendas feitas no balcao.
Tudo sendo usado simultaneamente....
Invariavelmente estou recebendo mensagem de que determinada alteracao nao pode ser feita porque aquele registro foi alterado por outro usuario. (ApplyUpdate(0)).
Exemplo: no servidor, numGrid, coloco todos os Shampoos Seda, e comeco a alterar os precos de promocao.
No balcao, vendo meia duzia de shampoo seda.
Quando o servidor for dar Apply nas alteracoes dele, a mensagem ocorre e as alteracoes que deveriam ter sido aplicadas ao banco, nao o sao.
Que solucao posso ter para isso?!
Creio que seja um problema que TODOS enfrentamos, pois é algo corriqueiro. Apenas eu não tenho uma solucao. Que me sugerem?!
Obrigado.
Gilbertoloss
Posts
05/01/2006
Michael
Tente isso: no DataSetProvider, defina a propriedade [b:248c14b918]UpdateMode [/b:248c14b918]para [b:248c14b918]upWhereKeyOnly[/b:248c14b918], e no DataSet associado a ele, configure a propriedade [b:248c14b918]ProviderOptions[/b:248c14b918]->[b:248c14b918]pfInWhere [/b:248c14b918]para [b:248c14b918]False [/b:248c14b918]de todos os Fields, com exceção do campo que representa a chave primária, que deve ter tbm [b:248c14b918]ProviderOptions[/b:248c14b918]->[b:248c14b918]pfInKey [/b:248c14b918]igual a [b:248c14b918]True[/b:248c14b918].
Há uma vídeo aula no portal da DevMedia, produzida pelo meu amigo [b:248c14b918]Guinther Pauli[/b:248c14b918], que fala exatamente sobre isso. O acesso é restrito a assinantes ou leitores da revista ClubeDelphi. Se for o seu caso, acesse [url=https://www.devmedia.com.br/visualizacomponente.aspx?comp=548&site=3]esse link[/url].
O problema ocorre pq por default o [b:248c14b918]DataSetProvider [/b:248c14b918]monta as instruções SQL passando na cláusula [b:248c14b918]WHERE[/b:248c14b918] *todos* os campos da tabela. Então, se enquanto o [b:248c14b918]usuário A[/b:248c14b918] edita um registro e o [b:248c14b918]usuário B[/b:248c14b918] muda alguma coisa no mesmo registro e salva, quando o usuário A for dar post os dados na memória do ClientDataSet serão diferentes da tabela no servidor e o comando SQL vai falhar. Usando apenas a chave primária no WHERE, vc garante que isso não vai acontecer, pois dois registros não podem ter a mesma primary key.
[]´s
07/01/2006
Gilbertoloss
No entanto, considere seguinte situacao: usando Dbexpress, loja com com tres PC´s em checkout. Tenho em estoque 5 potes de maionese.
Cada checkout vende, ao mesmo tempo, um pote de maionese.
Ou seja: Estoque = 5, PDV 1 vende 1 item, PDV 2 vende 1 item, PDV 3 vende 1 item. So que essas transacoes ocorrem simultaneamente.
Ao final, qual sera o estoque do produto?!
PDV 1 viu que tinha 5, vendeu 1 ficaram 4.
PDV 2 viu que tinha 5, vendeu 1 ficaram 4.
PDV 3 viu que tinha 5, vendeu 1 ficaram 4.
Tentei usar RefreshRecord antes de gravar, mas ele apresenta um bug e nao funcionou.
Alguem tem alguma ideia de como resolver?!
Gilberto Machado Loss
Gerente de TI
Farmasoft Tecnologia Ltda
07/01/2006
Gilbertoloss
Unable to find record. No key specified.
Se alguem tiver conhecimento sobre como resolver, por favor, apresente-nos.
Obrigado.
Gilberto Machado Loss
Farmasoft Tecnologia Ltda
09/01/2006
Michael
O erro pode estar havendo pq não há nenhum campo marcado como chave na lista de campos retornados pela query em questão. Vc chegou a tentar a dica que eu disse acima?
Sobre o problema das atualizações, bom, se vc estiver fazendo via software - e é o que parece, tendo em vista a sua menção ao método [b:65f51bda9e]RefreshRecord [/b:65f51bda9e]- , então realmente vc terá que bolar um jeito de obter o valor atual da quantidade do produto antes de atualizá-lo.
Se estiver usando comandos SQL, vc pode melhorar isso com isolamentos de transações. Qual comando SQL vc está usando para atualizar os dados e qual o isolamento da sua transação?
Dê uma olhada, se puder, na vídeo-aula que eu mencionei.
[]´s
01/08/2006
Macario
utilizo os passos descritos acima, mas mesmo assim nao estou obtendo exito com o metodo RefreshRecord.
Minha chave é EMPRESA+CLIENTE+DOCUMENTO
no clientdataset esta como: pfInUpdate = true, pfinWhere=true e pfInKey=true;
esta combinaçao esta correta?
Mesmo após o ApplyUpdates(0), ele nao atualiza o registro, no qual deveria trazer o nome do cliente, nome da conta, etc. que fazem parte de outras tabelas.
Estou querendo evitar o refresh, pois a tabela contem muitos registros.
Grato.
8)
01/08/2006
Joaoshi
acredito que o ´nome do cliente, nome da conta, etc. que fazem parte de outras tabelas. ´ deveriam ser gravados no beforepost ClientDaset, assim você sai do refreshrecord.
Espero ter ajudado.
01/08/2006
Macario
Estes campos não são gravados, eles apenas são exibidos.
O que acontece é que na tabela de documentos, eu faço uso de left join para obter esses dados.
:roll:
01/08/2006
Joaoshi
Você inclui estes campos no ClientDataset e coloca tudo FALSE no providersFlag destes campos (update, where e key), ai no beforepost você atualiza os dados das ´outras tabelas´ e fica tudo beleza pro usuário.
Estes campos só fazem parte do ClientDataSet não serão atualizados no banco.
Espero ter ajudado.
01/08/2006
Renatacoimbra
crie uma trigger After Insert na tabela de Itens de vendas, daí o próprio banco faz a baixa pra vc.
Um exemplo usando FireBird:
CREATE TRIGGER BAIXA_ESTOQUE FOR CUPOM_ITENS ACTIVE AFTER INSERT POSITION 0 AS begin update produtos set ESTOQUE_ATUAL = ESTOQUE_ATUAL - NEW.qtde where ID = new.ID_PRODUTO; end
Clique aqui para fazer login e interagir na Comunidade :)