Fórum Transações com DbExpress de forma Bidirecional #268226

11/02/2005

0

Gostaria de saber de vocês como posso realizar inserções , atualizações e excluir dados como o componente dbexpress de forma bidirecional.


Desde já agradeço a atenção.


Lnunes

Lnunes

Responder

Posts

11/02/2005

Gandalf.nho

Use um ClientDataSet em conjunto


Responder

Gostei + 0

11/02/2005

Lnunes

Já estou utilizando o ClientDataSet em conjunto ,contudo após a realização
do comando de inserção ,os dados continuam na memôria e só são gravados fisicamente quando saio da aplicação.

Gostaria se possivel que alguém disponibiliza-se um exemplo de transações
com insert,update e delete utilizando o SQLdataset da paleta dbExpress
juntamente com o ClientDataSet.

Desde já agradeço a atenção de todos.


Responder

Gostei + 0

11/02/2005

Laureano Pereira

Em que momento você executa um ApplyUpdates?

quanto fecha o form?

ou após inserir um registro...?

Dê uma olhada...

Abraços


Responder

Gostei + 0

11/02/2005

Vinicius2k

Colega,

Vc tem 3 opções :

[b:e724a2c70e]1. Não deixar explícito o controle da transação.[/b:e724a2c70e]

Quando vc utiliza TDataSetProvider + TClientDataSet, a Midas irá se encarregar das transações. Por exemplo, ao abrir um ClientDataSet ela (a Midas) irá iniciar uma transação, solicitar os dados ao TSQLDataSet, armazenar no buffer do TClientDataSet e fechar a transação. Isto é automático e não requer sua intervenção. Sua únicas providências devem ser utilizar o método ApplyUpdates do TClientDataSet quando desejar enviar as alterações ao banco de dados (neste momento a midas irá abrir uma transação, aplicar as atualizações nos dados (se for possível) e fechar a transação) e trabalhar o evento OnReconcileError do TClientDataSet para capturar os erros durante a aplicação das atualizações.
Ex:
SQLDataSet1.CommandText:= ´select ID, NOME from CLIENTES where ID = :id;
SQLDataSet1.ParamByName(´id´).AsInteger:= 1;
ClientDataSet1.Open; // Foi criada uma transação para fetch dos registros para o lado do cliente.
with ClientDataSet1 do
begin
  Append;
  FieldByName(´ID´).AsInteger:= 2005;
  FieldByName(´NOME´).AsString:= ´ClubeDelphi´;
  Post;
  ApplyUpdates(0); // Foi criada uma transação para envio das atualizações para o lado do servidor.
end;

Vale lembrar que o método ApplyUpdates nunca gera exceção, então, para saber se existiu algum erro, vc pode ler o valor do seu retorno (o método retorna o número de erros ocorridos) e/ou buscar, tratar e tomar providências baseadas na mensagem de erro no evento OnReconcileError.
No exemplo acima uma alteração :
if ApplyUpdates(0) > 0 then ShowMessage(´Ouve um erro.´)
  else ShowMessage(´Não houve erro´);

No evento OnReconcileError utilize, por exemplo :
ShowMessage(E.Message);


[b:e724a2c70e]2. Controlar explicitamente a transação mesmo utilizando um TClientDataSet[/b:e724a2c70e]
Esta opção é útil, principalmente quando se tem updates encadeados, com mestres-detalhes, por exemplo. Vc tira o controle da transação das ´mãos´ da Midas e toma você mesmo as providências que desejar.
Ex:
var 
  Transacao: TTransactionDesc;
begin
  SQLDataSet1.CommandText:= ´select ID, NOME from CLIENTES where ID = :id;
  SQLDataSet1.ParamByName(´id´).AsInteger:= 1;
  ClientDataSet1.Open; // Note que apenas o TClientDataSet deve ser aberto
  with ClientDataSet1 do
  begin
    Append;
    FieldByName(´ID´).AsInteger:= 2005;
    FieldByName(´NOME´).AsString:= ´ClubeDelphi´;
    Post;
    Transacao.TransactionID:= 1;
    Transacao.IsolationLevel:=  xilReadCommitted;
    SQLConnection1.StartTransaction(Transacao);
    if  ApplyUpdates(0) = 0 then
      SQLConnection1.Commit(Transacao)
    else SQLConnection1.Rollback(Transacao);
  end;

No exemplo acima eu mesclei as duas formas de trabalhar, deixando que a midas cuidasse da transação de leitura e fetch dos registros, mas assumi o controle da transação de aplicação das atualizações. Baseado no valor de retorno do ApplyUpdates eu efetuo commit ou rollback na transação.
Como eu disse isto é mais útil com updates encadeados, porque vc poderá voltar toda a transação se ocorrer erro em algum dos updates, por exemplo :
var 
  TudoOK: Boolean;
  Transacao: TTransactionDesc;
begin
  TudoOK:= False;
  Transacao.TransactionID:= 1;
  Transacao.IsolationLevel:=  xilReadCommitted;
  SQLConnection1.StartTransaction(Transacao);
  // Aplicando os updates
  if ClientDataSet1.ApplyUpdates(0) = 0 then
    if ClientDataSet2.ApplyUpdates(0) = 0 then
      if ClientDataSet3.ApplyUpdates(0) = 0 then
        if ClientDataSet4.ApplyUpdates(0) = 0 then
          TudoOK:= True;
  // Note que TudoOK só será true se não houver nenhum erro em nenhum dos Updates
  if TudoOK then
  begin
    SQLConnection1.Commit(Transacao);
    ShowMessage(´Atualizações OK.´);
  end
  else
  begin
    SQLConnection1.Rollback(Transacao);
    ShowMessage(´Ocorreram erros. Alterações descartadas.´);
  end;
end;


[b:e724a2c70e]3. Controle da transação sem uso de TClientDataSet.[/b:e724a2c70e]
Esta é uma forma mais simples de efetuar algumas operações no banco de dados. Ex :
var 
  Transacao: TTransactionDesc;
begin
  with SQLDataSet1 do
  begin  
    CommandText:= ´insert into CLIENTES (ID, NOME) values (:id, :nome)´;
    ParamByName(´id).AsInteger:= 2005;
    ParamByName(´nome´).AsString:= ´ClubeDelphi´;
    Transacao.TransctionID:= 1;
    Transacao.IsolationLevel:=  xilReadCommitted;
    SQLConnection1.StartTransaction(Transacao);
    try
      ExecSQL;
      SQLConnection1.Commit (Transacao);
    except
      on E: Exception do
      begin
        SQLConnection1.Rollback(Transacao);
        ShowMessage(´Ocorreram erros.´ + #13 + E.Message);
      end;
    end;
  end;
end;

Note que com o TSQLDataSet já é possível utilizar blocos try/except para proteger a operação e capturar os erros.

Bem... creio que seja isto. Cabe a você estudar e decidir quando, onde e como usar cada uma destas 3 formas.

Espero ter ajudado.
T+


Responder

Gostei + 0

11/02/2005

Lnunes

Eu utilizo ApplyUpdates após inserir o registro mas está ocorrendo o seguinte erro:

Project x.exe raised exception class EDatabaseError with message ´Field
´Codigo´ must have a value´ . Progress stopped. Use Step or Run to continue


Desde já agradeço a atenção de todos.


Responder

Gostei + 0

11/02/2005

Lnunes

Muito obrigado Vinicius2K e a todos que responderam a minha dúvida, agora acredito que poderei desenvolver a minha aplicação sem maiores problemas.

LNunes.


Responder

Gostei + 0

11/02/2005

Vinicius2k

Project x.exe raised exception class EDatabaseError with message ´Field ´Codigo´ must have a value´ . Progress stopped. Use Step or Run to continue

Isto ocorre quando um TField tem a sua propriedade Required setada para True e não recebe valor no momento do Post.
Quando vc utilizar Generators + Triggers para incrementar sua coluna código, ou mesmo campos auto-increment em outros SGBDs, mesmo a coluna sendo chave primária e not null, vc deverá setar a propriedade Required para False e não informar valor no Post.

Outro detalhe, editei a minha mensagem original, visto que utilizei :
[color=red:fad98df2a7]TTransactionDescription[/color:fad98df2a7] sendo o correto [color=green:fad98df2a7]TTransactionDesc[/color:fad98df2a7] e também [color=red:fad98df2a7]Transacao.ID[/color:fad98df2a7] sendo o correto [color=green:fad98df2a7]Transacao.TransactionID[/color:fad98df2a7]. Perdõe-me, só percebi os erros após a postagem.

T+


Responder

Gostei + 0

22/08/2005

Paulo Trajano

Colega, Vc tem 3 opções : [b:1e61dcbd28]1. Não deixar explícito o controle da transação.[/b:1e61dcbd28] [b:1e61dcbd28]2. Controlar explicitamente a transação mesmo utilizando um TClientDataSet[/b:1e61dcbd28] [b:1e61dcbd28]3. Controle da transação sem uso de TClientDataSet.[/b:1e61dcbd28] ... Cabe a vc decidir ....



Caro amigo Vina (há qto tempo hein!!)

Como vai essa força?
Como vc já me ajudou muito com DBXpress há mais de um ano atrás, gostaria que vc esclarecesse pra mim e pro restante do pessoal qual dos três métodos acima vc usa e que acha melhor para trablahar e menos problemático. (Abusei agora :lol: )

Abraço a todos


Responder

Gostei + 0

03/09/2005

Vinicius2k

Salve Paulinho !

Desculpe a demora...

Eu uso, os métodos 2 e 3. Essencialmente, o método 2 e, principalmente, para entrada de dados. O método 3 em operações de carga de dados, como importação/exportação de arquivos, por exemplo.

Depende muito de qual é a forma ideal para a rotina em questão, mas nunca abandono o controle da transação.

Abraços.
Vina.


Responder

Gostei + 0

16/01/2006

Macario

Ola Vinicius2K.

Estes seus esclarecimentos são de muito valor, parabéns.

Agora uma duvida sobre esse TTransactionDesc, ele se encontra dentro da unit dbExpress.pas, eu tenho que inclui-la em toda parte que chamar uma transação? Ou pode ser uma variavel global?

:roll:

Grato.


Responder

Gostei + 0

16/01/2006

Vinicius2k

Olá !

Eu prefiro mantê-la no escopo da minha classe de manipulação de dados, porém não vejo problema em que ela seja global.

T+


Responder

Gostei + 0

20/02/2006

Helio Nascimento

Olá Vinicius

Voltando a discusão sobre o assunto gostaria de usar dos seus conhecimentos para esclarecer-me e ensinar-me o que segue:

Tenho uma aplicação que digita pedidos.
Esta utilizando o D7 + DBExpress e utilizo o Trio do DBExpress sem problemas - Banco Firebird 1.5.3

Uma Tabela de Pedidos e outra de Itens do Pedido. Até ai tudo bem porem está me dando problemas com a lentidao do applyupdates(0) que esta sendo aplicado a cada item digitado. Ai vem a pergunta ....

Como Faço para fazer o ApplyUpdates(0) somente no final da digitação total deste pedido? - O Que devo confirmar nestes tres componentes?

Os supermercados fazem assim não é ... pois a gente vê depois de pagar a conta uma mensagem --´Aguarde atualizando o Banco ´

Aguardo sua resposta/Obrigado/Hélio


Responder

Gostei + 0

20/02/2006

Helio Nascimento

Vinicius ... desculpe mas escrevi errado .. a pergunta é ´ O que devo fazer para configurar estes tres componentes ? ´ Há Algum macete a fazer no

[color=blue:3755c06c3b] SQLDataSet[/color:3755c06c3b] - Ou no [color=blue:3755c06c3b] DataSetProvider[/color:3755c06c3b] - ou no -[color=blue:3755c06c3b]ClientDataSet[/color:3755c06c3b]

Helio


Responder

Gostei + 0

20/02/2006

Vinicius2k

Helio,

Nestes casos é melhor efetuar os ApplyUpdates apenas no final de tudo. Você não precisará configurar nenhuma propriedade no TClientDataSet, basta não chamar o [b:d680a44792]ApplyUpdates[/b:d680a44792] após o [b:d680a44792]Post[/b:d680a44792].

Sua ligação ´Pedidos -> Ítens´ é mestre-detalhe explícito (MasterSource de ítens = DataSource de pedidos)?
Eu não uso mestre-detalhe desta forma, prefiro fazer ´no braço´, então a sequência que eu sigo é, basicamente, a seguinte.

1. Insiro mestre e encerro apenas com Post.
2. Insiro detalhes, também encerrando apenas com Post. Porém aqui eu uso um CDS não ligado ao banco, apenas como tabela de memória.
3. Inicio a transação.
3. ApplyUpdates do mestre. Neste momento eu já tenho a chave primária que vai fazer a ligação com os detalhes, caso seja auto-incremento.
4. Percorro meu CDS de memória aonde estão os detalhes e insiro os dados no CDS ligado ao Banco, acrescentando aos registros o número da chave que faz a ligação com o mestre.
5. ApplyUpdates no CDS de detalhe ligado ao banco.
6. Se foi tudo OK, confirmo a transação, caso contrário volto toda ela.

T+


Responder

Gostei + 0

21/02/2006

Helio Nascimento

Hélio, Uma das grandes vantagens do CDS é servir como tabela de memória, aonde você cria os TFields (idênticos aos do que está ligado ao banco, neste caso) e chama o método ´CreateDataSet´. Feito isto, você insere, edita, deleta, exatamente como em qualquer descendente de TDataSet. Você pode usar DBAware ou não, a escolha é sua... Caso não utilize, você poderá atribuir valores aos TFields ou lê-los diretamente através da propriedade FieldByName. Ex:
SeuCDSTemporario.FieldByName(´Nome_do_Field´).AsString := ´Valor´;
Veja estes artigos: http://www.activedelphi.com.br/print.php?sid=14 http://www.inf.ufsc.br/~prass/artigos/artigo07.html T+



Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar