Transações com DbExpress de forma Bidirecional
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.
Desde já agradeço a atenção.
Lnunes
Curtidas 0
Respostas
Gandalf.nho
11/02/2005
Use um ClientDataSet em conjunto
GOSTEI 0
Lnunes
11/02/2005
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.
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
Laureano Pereira
11/02/2005
Em que momento você executa um ApplyUpdates?
quanto fecha o form?
ou após inserir um registro...?
Dê uma olhada...
Abraços
quanto fecha o form?
ou após inserir um registro...?
Dê uma olhada...
Abraços
GOSTEI 0
Vinicius2k
11/02/2005
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:
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 :
No evento OnReconcileError utilize, por exemplo :
[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:
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 :
[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 :
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+
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
Lnunes
11/02/2005
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.
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
Lnunes
11/02/2005
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.
LNunes.
GOSTEI 0
Vinicius2k
11/02/2005
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+
GOSTEI 0
Paulo Trajano
11/02/2005
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
GOSTEI 0
Vinicius2k
11/02/2005
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.
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
Macario
11/02/2005
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.
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
Vinicius2k
11/02/2005
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+
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
Helio Nascimento
11/02/2005
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
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
Helio Nascimento
11/02/2005
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
[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
Vinicius2k
11/02/2005
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+
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
Helio Nascimento
11/02/2005
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:
Veja estes artigos:
http://www.activedelphi.com.br/print.php?sid=14
http://www.inf.ufsc.br/~prass/artigos/artigo07.html
T+
SeuCDSTemporario.FieldByName(´Nome_do_Field´).AsString := ´Valor´;
GOSTEI 0
Helio Nascimento
11/02/2005
Nossa, cara, assim foi demais !! Se eu não aprender agora ... nunca mais! Valeu pelos links/ e explanação sobre o assunto. Acho que a galera agora vai ao delírio.Adeus reclamação de lentidão , e dos famosos por que disto e por que daquilo, ´não esta funcionando direito´ ´ acho que é a máquina´ e vai por aí afora as reclamações daquela pecinha que fica entre o teclado e a cadeira chamado de ´usuário´ .. Valeu até breve!!
Sds/Hélio
Sds/Hélio
GOSTEI 0
Azimute-al
11/02/2005
vinicius, vc poderia mostrar algum exemplo utilizando transacoes com mestre detalhes?
GOSTEI 0
Vinicius2k
11/02/2005
Colega,
[url=http://forum.clubedelphi.net/viewtopic.php?p=249362#249362]Neste post de outro tópico[/url], eu exemplifico uma das formas de fazê-lo. Apesar do assunto não ser exatamente o mesmo, o tópico todo é interessante... talvez lhe ajudar lê-lo todo.
Se o exemplo não lhe servir, poste aqui novamente. ;)
[url=http://forum.clubedelphi.net/viewtopic.php?p=249362#249362]Neste post de outro tópico[/url], eu exemplifico uma das formas de fazê-lo. Apesar do assunto não ser exatamente o mesmo, o tópico todo é interessante... talvez lhe ajudar lê-lo todo.
Se o exemplo não lhe servir, poste aqui novamente. ;)
GOSTEI 0
Azimute-al
11/02/2005
Prezado Vinicius,
segui sua dica e criei as transacoes que estao funcionado sem problema para inclusao e alteracao.
porém, no exclusao dos registro da tabela mestre quando nao possue registros na tabela detalhe, apos a linha:
Dados.TbComanda.Delete;
ocorre o seguinte erro.
´Record not found or changed by another user´
pergunto:
estou executado o delete no local correto ou tem que ter um tratamento especial de transacao para deletar registros?
O erro so ocorre quando insiro um novo registro na tabela mestre, se sair e entrar novamento posso excluir sem problemas. O que esta acontecendo?
segui sua dica e criei as transacoes que estao funcionado sem problema para inclusao e alteracao.
porém, no exclusao dos registro da tabela mestre quando nao possue registros na tabela detalhe, apos a linha:
Dados.TbComanda.Delete;
ocorre o seguinte erro.
´Record not found or changed by another user´
pergunto:
estou executado o delete no local correto ou tem que ter um tratamento especial de transacao para deletar registros?
O erro so ocorre quando insiro um novo registro na tabela mestre, se sair e entrar novamento posso excluir sem problemas. O que esta acontecendo?
//botao excluir procedure TFrm_Comanda1.SpeedButton3Click(Sender: TObject); var TudoOK: Boolean; Transacao: TTransactionDesc; begin if MessageDlg(´Deseja Excluir o Registro?´, mtConfirmation, [mbYes, mbNo], 0) = mrNo then Abort Else Begin TudoOK:= False; // Definindo instrução para o transacao Transacao.TransactionID:= 1; Transacao.IsolationLevel:= xilReadCommitted; Dados.Conexao.StartTransaction(Transacao); Try //deletando tabela mestre Dados.TbComanda.Delete; if Dados.TbComanda.ApplyUpdates(0) = 0 then Begin if Dados.TbItensComanda.ApplyUpdates(0) = 0 then Begin if Dados.TbItensFormasPgto.ApplyUpdates(0) = 0 then Begin Dados.TbComanda.Edit; If not(Dados.TbItensComanda.Eof) then Begin //atualizando Tabela de Detalhes Dados.TbItensComanda.Edit; Dados.TbItensComanda.Post; end; If not(Dados.TBItensFormasPgto.Eof) then Begin //atualizando tabela de Formas de Pagamento Dados.TbItensFormasPgto.Edit; Dados.TbItensFormas.PgtoPost; end; TudoOK := True; End; End; End; except TudoOK := False; end;
GOSTEI 0
Vinicius2k
11/02/2005
Colega,
Você está utilizando Nested Datasets para o mestre/detalhe?
Você poderia postar seu código novamente comentando-o? Não entendi trechos como este:
Aonde você edita e logo em seguida posta o DataSet sem realizar nenhuma operação.
Posso lhe adiantar que, normalmente, nos processos de exclusão controlados manualmente, os detalhes devem ser excluídos antes do mestre, caso contrário você estará violando regras de integridade referencial.
Você está utilizando Nested Datasets para o mestre/detalhe?
Você poderia postar seu código novamente comentando-o? Não entendi trechos como este:
If not(Dados.TbItensComanda.Eof) then Begin //atualizando Tabela de Detalhes Dados.TbItensComanda.Edit; Dados.TbItensComanda.Post; end;
Aonde você edita e logo em seguida posta o DataSet sem realizar nenhuma operação.
Posso lhe adiantar que, normalmente, nos processos de exclusão controlados manualmente, os detalhes devem ser excluídos antes do mestre, caso contrário você estará violando regras de integridade referencial.
GOSTEI 0
Azimute-al
11/02/2005
Só estou utilizando os componentes SQLConnection e SQLClientDataSet;
Eu não tenho que executar o post para salvar?
1 - excluo itens de TbComanda
2 - verifico se existe itens em detalhes, caso exista eu posto.
alterei pas IsEmpty e o erro continua.
No Banco de Dados utilizo o seguinte:
ALTER TABLE ´ITENSCOMANDA´ ADD CONSTRAINT ´ITMOVCOMA´ FOREIGN KEY (´SEQUENCIA´) REFERENCES COMANDAS (´SEQUENCIA´) ON UPDATE CASCADE ON DELETE CASCADE;
É que não estava funcionando e tentei verificar se existe ou não dados na tabela detalhes.
comentei as linha e ficou assim:
O que eu preciso é permitir a exclusao sem erros na tabela mestre, caso o usuario não informe itens na tabela detalhes. Quando o usuario realiza o primeiro movimento na tab. mestre e desiste excluindo o documento. O erro só é apresentado no primeiro lancamento, ou seja, quando nao existe nenhum registro em TbComanda e TbItenscomanda.
Eu não tenho que executar o post para salvar?
1 - excluo itens de TbComanda
2 - verifico se existe itens em detalhes, caso exista eu posto.
alterei pas IsEmpty e o erro continua.
No Banco de Dados utilizo o seguinte:
ALTER TABLE ´ITENSCOMANDA´ ADD CONSTRAINT ´ITMOVCOMA´ FOREIGN KEY (´SEQUENCIA´) REFERENCES COMANDAS (´SEQUENCIA´) ON UPDATE CASCADE ON DELETE CASCADE;
É que não estava funcionando e tentei verificar se existe ou não dados na tabela detalhes.
comentei as linha e ficou assim:
procedure TFrm_Comanda1.SpeedButton3Click(Sender: TObject); var TudoOK: Boolean; Transacao: TTransactionDesc; begin if MessageDlg(´Deseja Excluir o Registro?´, mtConfirmation, [mbYes, mbNo], 0) = mrNo then Abort Else Begin TudoOK:= False; // Definindo instrução para o transacao Transacao.TransactionID:= 1; Transacao.IsolationLevel:= xilReadCommitted; Dados.Conexao.StartTransaction(Transacao); try //Deletar o registro da tabela mestre Dados.TbComanda.Delete; if Dados.TbComanda.ApplyUpdates(0) = 0 then Begin if Dados.TbItensComanda.ApplyUpdates(0) = 0 then Begin if Dados.TbItensFormas.ApplyUpdates(0) = 0 then Begin //postar tabela mestre Dados.TbComanda.Edit; Dados.TbComanda.Post; //caso antes do delete exista registro na tabela detalhe gravar, pois, as informacoes ja foram excluidas com o SQL no Banco de Dados. //sem o edit apresentava erro informando que a tabela não estava em modo de edicao. If not(Dados.TbItensComanda.IsEmpty) then Begin Dados.TbItensComanda.Edit; Dados.TbItensComanda.Post; end; //caso exista registro na tabela de pagamentos grava //sem o edit apresentava erro informando que a tabela não estava em modo de edicao. If not(Dados.TBItensFormas.IsEmpty) then Begin Dados.TbItensFormas.Edit; Dados.TbItensFormas.Post; end; TudoOK := True; End; End; End; except TudoOK := False; end; // Note que TudoOK só será true se não houver nenhum erro em nenhum dos Updates if TudoOK then begin Dados.Conexao.Commit(Transacao); end else begin Dados.Conexao.Rollback(Transacao); ShowMessage(´Ocorreram erros. Operações descartadas.´); Dados.TBComanda.Cancel; end; end;
O que eu preciso é permitir a exclusao sem erros na tabela mestre, caso o usuario não informe itens na tabela detalhes. Quando o usuario realiza o primeiro movimento na tab. mestre e desiste excluindo o documento. O erro só é apresentado no primeiro lancamento, ou seja, quando nao existe nenhum registro em TbComanda e TbItenscomanda.
GOSTEI 0
Vinicius2k
11/02/2005
Colega,
A constraint no BD excluindo os detalhes quando um mestre é excluído é a melhor forma de trabalhar.
Neste caso, você não precisa fazer nada com os detalhes. Basta excluir o mestre e o próprio banco se encarrega de excluir os detalhes.
O código se resumiria a este:
Você não precisa, editar/postar os outros CDSs... Honestamente, não vejo o porque destas operações no seu código.
Não entendi o que você quis dizer com este trecho:
A constraint no BD excluindo os detalhes quando um mestre é excluído é a melhor forma de trabalhar.
Neste caso, você não precisa fazer nada com os detalhes. Basta excluir o mestre e o próprio banco se encarrega de excluir os detalhes.
O código se resumiria a este:
procedure TFrm_Comanda1.SpeedButton3Click(Sender: TObject); var TudoOK: Boolean; Transacao: TTransactionDesc; begin if MessageDlg(´Deseja Excluir o Registro?´, mtConfirmation, [mbYes, mbNo], 0) = mrNo then Abort Else Begin TudoOK:= False; Transacao.TransactionID := 1; Transacao.IsolationLevel := xilReadCommitted; Dados.Conexao.StartTransaction(Transacao); try Dados.TbComanda.Delete; if Dados.TbComanda.ApplyUpdates(0) = 0 then TudoOK := True; except TudoOK := False; end; end; if TudoOK then Dados.Conexao.Commit(Transacao) else begin Dados.Conexao.Rollback(Transacao); ShowMessage(´Ocorreram erros. Operações descartadas.´); end;
Você não precisa, editar/postar os outros CDSs... Honestamente, não vejo o porque destas operações no seu código.
Não entendi o que você quis dizer com este trecho:
//caso antes do delete exista registro na tabela detalhe gravar, pois, [color=red:74f37cb355]as informacoes ja foram excluidas com o SQL no Banco de Dados[/color:74f37cb355].
//sem o edit apresentava erro informando que a tabela não estava em modo de edicao.
GOSTEI 0
Azimute-al
11/02/2005
Caro Vinicius,
Antes de ler estes topicos eu usava o seginte:
Dados.TbComanda.ApplyUpdates(-1);
Dados.TbComanda.Refresh;
Pergunto:
O ApplyUpdates(0) ele já realiza a gravação no BD sem precisar do Post?
Para usar o post a tabela nao deve estar no status de Insert ou Edit?
Antes de ler estes topicos eu usava o seginte:
Dados.TbComanda.ApplyUpdates(-1);
Dados.TbComanda.Refresh;
Pergunto:
O ApplyUpdates(0) ele já realiza a gravação no BD sem precisar do Post?
Para usar o post a tabela nao deve estar no status de Insert ou Edit?
GOSTEI 0
Vinicius2k
11/02/2005
Colega,
Não. O post antes do ApplyUpdates é necessário após [i:fb555abf02]Insert[/i:fb555abf02], [i:fb555abf02]Append[/i:fb555abf02] ou [i:fb555abf02]Edit[/i:fb555abf02] no DataSet. Porém, [b:fb555abf02]não é necessário[/b:fb555abf02] no [i:fb555abf02]Delete[/i:fb555abf02].
Acho que é neste ponto que você está ´pecando´...
Não. O post antes do ApplyUpdates é necessário após [i:fb555abf02]Insert[/i:fb555abf02], [i:fb555abf02]Append[/i:fb555abf02] ou [i:fb555abf02]Edit[/i:fb555abf02] no DataSet. Porém, [b:fb555abf02]não é necessário[/b:fb555abf02] no [i:fb555abf02]Delete[/i:fb555abf02].
Acho que é neste ponto que você está ´pecando´...
GOSTEI 0
Cd.degrande
11/02/2005
Ola Vinícius, Estive pesquisando aqui no forum para resolver o meu problema com mestre-detalhe usando a Tecnologia DBExpress e encontrei o seu post que se encaixou como uma luva no que estou pretendendo fazer em minhas novas aplicações:
´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.
´
Porém estou com dificuldades no passo 3: pegar a chave primária da tabela mestre, sendo que este campo seria um AutoIncremental no banco(Identity do SQLServer ou com generator no FireBird). Ao efetuar o ApplyUpdates o novo valor gerado no banco não é retornado para a aplicação, no campo do ClientDataSet.
Se puder me ajudar agradeço.
t+
´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.
´
Porém estou com dificuldades no passo 3: pegar a chave primária da tabela mestre, sendo que este campo seria um AutoIncremental no banco(Identity do SQLServer ou com generator no FireBird). Ao efetuar o ApplyUpdates o novo valor gerado no banco não é retornado para a aplicação, no campo do ClientDataSet.
Se puder me ajudar agradeço.
t+
GOSTEI 0