Atualizacao Simultanea de Tabelas FireBird x DbExpress....

05/01/2006

Ola, pessoal. Tenho seguinte problema:
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

Respostas

05/01/2006

Michael

Olá!

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=http://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


Responder Citar

07/01/2006

Gilbertoloss

Ok, eu entendi bem sim!
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


Responder Citar

07/01/2006

Gilbertoloss

A proposito, o erro do RefreshRecord é o seguinte:
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


Responder Citar

09/01/2006

Michael

Olá!

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


Responder Citar

01/08/2006

Macario

Olá.

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)


Responder Citar

01/08/2006

Joaoshi

Macario,
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.


Responder Citar

01/08/2006

Macario

Ola.


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:


Responder Citar

01/08/2006

Joaoshi

Colega,

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.


Responder Citar

01/08/2006

Renatacoimbra

porque vc você não deixar o Servidor de BD fazer a baixa pra você ?

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




Responder Citar