Fórum Transações com DbExpress de forma Bidirecional #268226
11/02/2005
0
Desde já agradeço a atenção.
Lnunes
Curtir tópico
+ 0Posts
11/02/2005
Gandalf.nho
Gostei + 0
11/02/2005
Lnunes
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.
Gostei + 0
11/02/2005
Laureano Pereira
quanto fecha o form?
ou após inserir um registro...?
Dê uma olhada...
Abraços
Gostei + 0
11/02/2005
Vinicius2k
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+
Gostei + 0
11/02/2005
Lnunes
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.
Gostei + 0
11/02/2005
Lnunes
LNunes.
Gostei + 0
11/02/2005
Vinicius2k
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+
Gostei + 0
22/08/2005
Paulo Trajano
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
Gostei + 0
03/09/2005
Vinicius2k
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.
Gostei + 0
16/01/2006
Macario
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.
Gostei + 0
16/01/2006
Vinicius2k
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+
Gostei + 0
20/02/2006
Helio Nascimento
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
Gostei + 0
20/02/2006
Helio Nascimento
[color=blue:3755c06c3b] SQLDataSet[/color:3755c06c3b] - Ou no [color=blue:3755c06c3b] DataSetProvider[/color:3755c06c3b] - ou no -[color=blue:3755c06c3b]ClientDataSet[/color:3755c06c3b]
Helio
Gostei + 0
20/02/2006
Vinicius2k
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+
Gostei + 0
21/02/2006
Helio Nascimento
SeuCDSTemporario.FieldByName(´Nome_do_Field´).AsString := ´Valor´;
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)