Estou utilizando a versão XE, e no
momento estou implementando um servidor de aplicação usando a arquitetura
DataSnap. Um impasse que estou enfrentando é o seguinte:
No servidor de aplicação estão
implementadas as regras de negócio através de métodos (Server Methods) com seus
respectivos parâmetros, deixando todo o controle transacional encapsulado, e
transparente à aplicação cliente. Ou seja, a aplicação cliente consumirá o
método, sem precisar realizar controle transacional, e nem também passar
instruções SQL.
Na aplicação cliente faço uso de
recursos da VCL como os ClientDataSets ligados a DataSetProviders no servidor
de aplicação, bem como dos controles Dataware (DBedit, DBgrid, etc), pois o
ganho de produtividade e recursos de uma interface gráfica rica não podem ser
desconsiderados.
No entanto, existem situações onde é
preciso envolver as operações de ClientDatasets (ApplyUpdates) em uma
transação, mas estas estão encapsuladas no servidor. Não sei se estou sendo
claro, mas o que eu desejo é colocar as operações realizadas no(s) ClientDataset(s)
dentro de um contexto transacional do
servidor de aplicação onde outras rotinas referentes à regra de negócio em
questão estariam implementadas. Com isto, se teria de uma maneira simples a
consistência entre os dados apresentados na aplicação ao usuário e o estado do
Banco de Dados.
Pesquisei na web, e este impasse tem
sido relatado por alguns. Acredito que solução pode estar em passar o Delta dos
ClientDataSets envolvidos para aplicação servidora e esta através dos
respectivos DataSetProviders realize o ApplyUpdates. (Ex:
TDataSetProvider.ApplyUpdates(Delta, MaxErrors, ErrorCount);). Fiz uns testes e
ocorreram alguns erros na chamada do método e passagem do parâmetro do tipo
Delta. Porém, acho que seja preciso serializar os Deltas (OleVariant) para
passá-los como parâmetro para aplicação servidora. Este exemplo do Erick Sasse
mostra uma solução usando Remote Objects SDK, talvez o caminho seja por aí:
É isso aí pessoal! Desafio lançado!
então, no cliente, você faz algo assim:
try
Servidor.AbreTransacao; // método no servidor
cds1.ApplyUpdates(-1); // cds no cliente
cds2.ApplyUpdates(-1); // cds no cliente
cds3.ApplyUpdates(-1); // cds no cliente
Servidor.ConfirmaTransacao; // método no servidor
except
on E:Exception do
begin
ShowMessage('Erro ao executar procedimento. Msg original: '+E.Message);
Servidor.CancelaTransacao; // método no servidor
end;
end;
implemente o ReconcileError de cada Dataset para levantar uma exceção caso encontre algum problema e veja se dá certo.
Não sei se estou sendo claro, mas o que eu desejo é colocar as operações realizadas no(s) ClientDataset(s) dentro de um contexto transacional do servidor de aplicação onde outras rotinas referentes à regra de negócio em questão estariam implementadas. Com isto, se teria de uma maneira simples a consistência entre os dados apresentados na aplicação ao usuário e o estado do Banco de Dados.
você pode explicar melhor esse seu caso ?
vamos supor que no servidor haja estes métodos:
servidor.geralancamentoscontabeis
---------------------------------------------
- abre a transacao.
- faz a apuração do que deve ser lancado.
- incrementa os lotes de lançamento.
- efetua os lançamentos.
- confirma a transacao
servidor.movimentacaodeestoquenf
---------------------------------------------
- abre a transacao.
- varre todos os itens da nf e faz a movimentacao (se nf de saida, reduz o saldo, senão, incrementa)
- manipula os lotes de produto
- confirma a transacao
servidor.geratitulosfinanceiro
------------------------------------
- abre a transacao.
- avalia notafiscal (entrada ou saída) e verifica a condição de pagamento utilizada
- gera o título e as parcelas no financeiro (se nf de saída, gera contas a receber, se não, contas a pagar)
- confirma a transacao
agora você precisa fazer, a partir do cliente, a chamada a dois métodos, nesta ordem:
servidor.movimentacaodeestoquenf
servidor.geratitulosfinanceiro
porém se o método servidor.geratitulosfinanceiro (o segundo) der algum problema, o primeiro método já estárá "comitado", certo? o que pode ocasionar um problema de consistência nos dados.
para que isso não aconteça, altere o servidor para:
servidor.geralancamentoscontabeis
---------------------------------------------
- verifica se há uma transação aberta. se não tiver, abre aqui.
- faz a apuração do que deve ser lancado.
- incrementa os lotes de lançamento.
- efetua os lançamentos.
- se a transação foi aberta aqui, confirma a transacao
servidor.movimentaestoquenf
---------------------------------------------
- verifica se há uma transação aberta. se não tiver, abre aqui.
- varre todos os itens da nf e faz a movimentacao (se nf de saida, reduz o saldo, senão, incrementa)
- manipula os lotes de produto
- se a transação foi aberta aqui, confirma a transacao
servidor.geratitulosfinanceiro
------------------------------------
- verifica se há uma transação aberta. se não tiver, abre aqui.
- avalia notafiscal (entrada ou saída) e verifica a condição de pagamento utilizada
- gera o título e as parcelas no financeiro (se nf de saída, gera contas a receber, se não, contas a pagar)
- se a transação foi aberta aqui, confirma a transacao
servidor.abretransacao
-----------------------------
- se houver uma transacao aberta, retorna falso, senão abre a transação e retorna verdadeiro
servidor.confirmatransacao
-----------------------------
- se houver uma transacao aberta, confirma a transacao (commit) e retorna verdadeiro, senão retorna falso
servidor.cancelatransacao
-----------------------------
- se houver uma transacao aberta, cancela a transacao (rollback) e retorna verdadeiro, senão retorna falso
note que todos os métodos estão no servidor.
agora, no cliente, você sabe que precisará chamar dois métodos do servidor, porém eles precisam trabalhar em conjunto. foi aí que eu sugeri:
try
servidor.abretransacao; // transação no servidor, não no cliente
cds1.applyupdates(-1);
cds2.applyupdates(-1);
servidor.movimentaestoquenf // método executado no servidor, porém não abrirá a transação
servidor.geratitulosfinanceiro // método executado no servidor, porém não abrirá a transação
servidor.confirmatransacao; // confirma a transação no servidor
except
servidor.cancelatransacao; // cancela a transação no servidor
end;
não vejo outra forma de fazer algo desse tipo.
todos os AllApplayUpdates do client no Servidor .. Acredito que não so na tecnologia DataSnap , mas também em Desktop e com alguma adaptação funcionara tambpém em client Servidor tradicional. Mas o proposito inicial da classe é o DataSnap
http://marcosalles.wordpress.com/2011/07/09/applayupdate-aplicacao-de-atualizacoes-para-mais-de-um-clientdataset-em-uma-unica-transacao-com-datasnap/
A vantagem da classe é o reaproveitamento bem como tirar a resposanbilidade de um form ou um dataModulo
ou mesmo de outra classe de ter que fazer isto . Além de facilitar a manutenção . A classe utiliza RTTI e não tem nenhum aclopamento com a classe Proxy gerada . Que dizer para vários servidores DataSnap desde que em uma questão contratual implemente a função AllApplayUpdates ( sobe o risco de se gerar uma exceção)
sabadão .. frio .. coçando...









