Transações com DbExpress de forma Bidirecional

Delphi

11/02/2005

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

Curtidas 0

Respostas

Gandalf.nho

Gandalf.nho

11/02/2005

Use um ClientDataSet em conjunto


GOSTEI 0
Lnunes

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.


GOSTEI 0
Laureano Pereira

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


GOSTEI 0
Vinicius2k

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:
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

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.


GOSTEI 0
Lnunes

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.


GOSTEI 0
Vinicius2k

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

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

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.


GOSTEI 0
Macario

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.


GOSTEI 0
Vinicius2k

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+


GOSTEI 0
Helio Nascimento

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


GOSTEI 0
Helio Nascimento

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


GOSTEI 0
Vinicius2k

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+


GOSTEI 0
Helio Nascimento

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:
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+



GOSTEI 0
Helio Nascimento

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


GOSTEI 0
Azimute-al

Azimute-al

11/02/2005

vinicius, vc poderia mostrar algum exemplo utilizando transacoes com mestre detalhes?


GOSTEI 0
Vinicius2k

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. ;)


GOSTEI 0
Azimute-al

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?

//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

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:
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

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:


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

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:
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

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?


GOSTEI 0
Vinicius2k

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´...


GOSTEI 0
Cd.degrande

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+


GOSTEI 0
POSTAR