Qual a maneira correta de alterar um formulario mestre/detal

10/06/2008

4

Pessoal estou com um problema aqui, tenho que fazer um form para alterar duas tabelas relacionadas mestre/detalhe

Só que a tabela detalhe eu tenho que trazer todos os itens que ja foram gravados ai tem os botões inserir - alterar - excluir - gravar - cancelar

esta alteração fica dentro do mesmo form que tambem pode ser alterado que é a tabela mestre.

Ele vem no form na seguinte maneira, tem alguns tabsheets aonde primeiro abro para alterar algo na tabela mestre e depois no tabsheet seguinte tem os dados da tabela detalhe. Só que esta alteração na tabela detalhe tem que ser feita antes de gravar na tabela mestre, ai o problema, preciso gravar tipo temporario e depois no final quando for gravar na tabela mestre atualizar a tabela detalhe tambem. Pois se o usuario resolver no final cancelar tudo a tabela detalhe tem que excluir tambem as atualizações que foram feitas.

Se eu deixar para aplicar o applyupdates da tabela detalhe somente na hora de gravar os dados alterados da tabela mestre vem somente a ultima inclusão por exemplo que eu fiz na tabela detalhe, e se no caso tiver varias inclusões ai elas se perdem, por isso pensei gravar num dataset temporario e depois passar tudo de uma só vez no final. Mais quando fui fazer assim apareçeu um erro estranho:
[color=red:3b8ec4f249]´Espaço insuficiente de armazenamento para concluir a operação´[/color:3b8ec4f249] Este erro vem na segunda inclusão na tabela temporaria detalhe.

Então gostaria de saber qual é o procedimento correto de fazer este tipo de alteração em dias tabelas relacionadas?

Grato
Adriano


Responder

Posts

Será que a melhor saída para isso seria gravar em XML e se for cancelado destruir o que esta gravado em XML, ou gravado no final passar os valores e depois destruir também para um novo clientdataset.edit?


Responder
Será que a melhor saída para isso seria gravar em XML e se for cancelado destruir o que esta gravado em XML, ou gravado no final passar os valores e depois destruir também para um novo clientdataset.edit?
Acho que falei besteiras, não ia me adiantar de nada gravar em XML, desconsidere este ultimo post. Continua a duvida.


Responder

10/06/2008

Brunodsr

Olá,

O Enio teve uma dúvida parecida com a sua em outro tópico. Para trabalhar com master detail, vc tem que colocar as duas tabelas na mesma transação.

1. Start transaction;
2. Insert na tabela pai;
3. Insert na tabela filho;
4. Commit ou rollback.

O mesmo se aplica para alterar e excluir. Todas as alterações/inserções e deleções são executadas no banco apenas após o commit ou rollback.


Responder
Olá, O Enio teve uma dúvida parecida com a sua em outro tópico. Para trabalhar com master detail, vc tem que colocar as duas tabelas na mesma transação. 1. Start transaction; 2. Insert na tabela pai; 3. Insert na tabela filho; 4. Commit ou rollback. O mesmo se aplica para alterar e excluir. Todas as alterações/inserções e deleções são executadas no banco apenas após o commit ou rollback.
Ola Bruno, mais como posso aplicar um ´Commit/Rollbak´ em um sistema multcamadas? sendo que estou usando o DataSnap na camada client?

Estava pensando em fazer algum tipo de campo de ´Status´ gravar no banco e se o usuario cancelar a operação aplicar uma trigger desfazendo os dados que estão com o ´Status´ em alguma situação diferente que a definitiva na tabela filho. Mais não sei se vai ficar complicado ou se vai firar um negocio dificil de controla depois.

Agora se tiver como commitar somente no final ficaria mais facil, mais não sei fazer isso em multcamadas.


Responder

10/06/2008

Brunodsr

Apenas uma das suas camadas acessa o banco.. correto? Se sim..

Eu fiz uma aplicação assim:

Fachada (telas)
Controle (regras de negocio - TCliente, TPedidoCompra, TFornecedor)
Dados (Comandos SQL e conexao ao banco)

Para saber a ação a ser tomada eu sobrecarreguei o construtor do form, passando uma outra classe de parametros. Ex.:

Param := TParametros.Create(self);
Param.Action := AcAlterar;
Param.State := NoState;
...
...
...
Form := TFrPedidoCompra.Create(Application, Param);


Sempre que a ação era alterar, eu carregava os ítens lançados anteriormente, inserindo-os em um dataset (apenas em memória) e deixava ele disponível para novas inserções, modificações e deleções.

No momento em que eu confirmava a operação, enviada o próprio CDS do cabeçalho e o CDS dos ítens, que seriam usados pela minha classe de controle para pegar as modificações e jogar p/ o banco. Eu acesso as modificações pelas propriedades data e delta do CDS.

Dá uma olhada no help do delphi sobre o data e delta. Tem uns exemplos lá mostrando como se faz isso. Se não conseguir, me dá um toque.

Espero ter ajudado.


Responder
Confesso amigo que agora complicou, não sei se vou conseguir fazer da forma que vc explicou.
Desculpe não ter entendido, mais valeu pela força ai.


Responder
Pessoal, tá difícil (brabo mesmo), estou tentando usar um campo tipo STATUS para fazer este esquema todo, foi a única forma que eu consegui um resultado melhor, porém agora tem um problema de falta de reconhecimento dos dados no banco neste código aqui:

{:Grava os dados no banco}
  dm.ConInternetLocal.Open;
  try //começo do trecho try/finnaly
    if dsAltDEAR.DataSet.State in [dsEdit, dsInsert] then
      try //começo do trecho try/except
        dsAltDEAR.DataSet.Post;
        (dsAltDEAR.DataSet as TClientDataSet).ApplyUpdates(0);
        {:atualiza a tabela filho}
         with cdsAltTB_Proprietario do
         begin
           Close;
           CommandText := ´ UPDATE TB_PROPRIETARIO        ´+
                          ´ SET STATUS = :pSTATUS         ´+
                          ´ WHERE (ID_chave = :pID_chave) ´+
                          ´ and (STATUS = ´´N´´)          ´+
                          ´ and  (STATUS = ´´E´´)          ´;
           if FieldByName(´STATUS´).AsString = ´N´ then
              Params.ParamByName(´pSTATUS´).AsString    := ´G´
           else if FieldByName(´STATUS´).AsString = ´E´ then
              Params.ParamByName(´pSTATUS´).AsString    := ´F´;
           Params.ParamByName(´pid_chave´).AsString  := maskAltContDear.Text;
           Execute;
           {:Select para atualizar a grid}
           Close;
           CommandText := ´ select * from TB_PROPRIETARIO ´+
                          ´ where ID_chave = :pID_chave   ´;
           Params.ParamByName(´pid_chave´).AsString  := maskAltContDear.Text;
           Open;
         end;
         Dc_MessageDlg(´Dados gravados com sucesso´, mtInformation, [mbOk],0);
         {:atualiza os dados da tabela altDear}
         dsAltDEAR.DataSet.Close;
         dsAltDEAR.DataSet.Open;
      except
         on E:Exception do
         begin
           dc_MessageDlg(´Ocorreu um erro neste processo. ´ +#1313 +´Erro gerado: ´+13+
           E.Message + 1313 + ´Todo o processo foi abortado!´, mtError, [mbOk],0);
           Abort;
           dsAltDEAR.DataSet.Cancel;
         end;
      end; //Final try/except
  finally
     dm.ConInternetLocal.Close;
  end; //final do trecho try/finally


Aonde fiz um [b:f382c01c9b]debug[/b:f382c01c9b] linha a linha pra ver como estava o procedimento e percebi que o código pula este IF aqui
if FieldByName(´STATUS´).AsString = ´N´ then
              Params.ParamByName(´pSTATUS´).AsString    := ´G´
           else if FieldByName(´STATUS´).AsString = ´E´ then
              Params.ParamByName(´pSTATUS´).AsString    := ´F´;

Ou seja pelo que estou tentando fazer é: Se no banco tiver dados gravados com o STATUS N mudar para STATUS G e se tiver dados gravados com STATUS E mudar para STATUS F no update.

Então na hora de debugar ele entra no 1º IF e pula para o 2º IF que também pula para próxima linha ignorando o que está lá no banco, que tem dados com o STATUS N e E também.

Alguma idéia pessoal?

Grato
Adriano


Responder
Pessoal, não sei se é a melhor forma, mais resolveu meu problema com uma tabela auxiliar assim

begin
  //inherited;
  {:Grava os dados no banco}
  dm.ConInternetLocal.Open;
  try //começo do trecho try/finnaly
    if dsAltDEAR.DataSet.State in [dsEdit, dsInsert] then
      try //começo do trecho try/except
        dsAltDEAR.DataSet.Post;
        (dsAltDEAR.DataSet as TClientDataSet).ApplyUpdates(0);
        {:atualiza a tabela filho}
         with cdsAltTB_Proprietario do
         begin
           Close;
           CommandText := ´ UPDATE TB_PROPRIETARIO        ´+
                          ´ SET STATUS = :pSTATUS         ´+
                          ´ WHERE (ID_chave = :pID_chave) ´+
                          ´ and (STATUS = ´´N´´)          ´+
                          ´ or (STATUS = ´´E´´)           ´;
          {:Traz o resultado do Status numa tabela Auxiliar}
           with qryAuxiliarTbPropr do
           begin
             Close;
             SQL.Clear;
             SQL.Text := ´ select STATUS from TB_PROPRIETARIO      ´+
                         ´ where STATUS = ´´N´´ or  STATUS = ´´E´´ ´;
             Open;
             DisableControls; {;fechas os controles para ir mais rápido}
             First; {:Primeiro registro}
             while not Eof do {:enquanto não for o fim, altera os parametros}
             begin
               if FieldByName(´STATUS´).AsString = ´N´ then
                  cdsAltTB_Proprietario.Params.ParamByName(´pSTATUS´).AsString      := ´G´
               else if FieldByName(´STATUS´).AsString = ´E´ then
                       cdsAltTB_Proprietario.Params.ParamByName(´pSTATUS´).AsString := ´F´;
               Next; {:próximo registro}
             end;
             EnableControls; {:abre novamente os controles}
           end;
           Params.ParamByName(´pid_chave´).AsString  := maskAltContDear.Text;
           Execute;
           {:Select para atualizar a grid}
           Close;
           CommandText := ´ select * from TB_PROPRIETARIO ´+
                          ´ where ID_chave = :pID_chave   ´;
           Params.ParamByName(´pid_chave´).AsString  := maskAltContDear.Text;
           Open;
         end;
         Dc_MessageDlg(´Dados gravados com sucesso´, mtInformation, [mbOk],0);
         {:atualiza os dados da tabela altDear}
         dsAltDEAR.DataSet.Close;
         dsAltDEAR.DataSet.Open;
      except
         on E:Exception do
         begin
           dc_MessageDlg(´Ocorreu um erro neste processo. ´ +1313 +´Erro gerado: ´+13+
           E.Message + 1313 + ´Todo o processo foi abortado!´, mtError, [mbOk],0);
           Abort;
           dsAltDEAR.DataSet.Cancel;
         end;
      end; //Final try/except
  finally
     dm.ConInternetLocal.Close;
  end; //final do trecho try/finally


ai adptei este trecho no código
{:Traz o resultado do Status numa tabela Auxiliar}
           with qryAuxiliarTbPropr do
           begin
             Close;
             SQL.Clear;
             SQL.Text := ´ select STATUS from TB_PROPRIETARIO      ´+
                         ´ where STATUS = ´´N´´ or  STATUS = ´´E´´ ´;
             Open;
             DisableControls; {;fechas os controles para ir mais rápido}
             First; {:Primeiro registro}
             while not Eof do {:enquanto não for o fim, altera os parametros}
             begin
               if FieldByName(´STATUS´).AsString = ´N´ then
                  cdsAltTB_Proprietario.Params.ParamByName(´pSTATUS´).AsString      := ´G´
               else if FieldByName(´STATUS´).AsString = ´E´ then
                       cdsAltTB_Proprietario.Params.ParamByName(´pSTATUS´).AsString := ´F´;
               Next; {:próximo registro}
             end;
             EnableControls; {:abre novamente os controles}
           end;



Responder
Alguma outra idéia de como se fazer isso?

Tratando por um campo é complicado e dificil, e não é 100¬ funcional, alem de um extenso código sem necessidade e depois de difícil manutenção.

A unica coisa que eu preciso é poder incluir, deletar e alterar na tabela filho sem passar para o banco ou se gravar no banco e na tabela pai que esta em modo de edição eu cancelar tudo na tabela filho retornar ao que estava antes gravado no banco.

Se eu deixo pra aplicar o applyupdates (tabe Filho) no final aponta para o erro ´Update Affected mode than 1 record´ se eu mudo o datasetprovider a propriedade Options->poAllowMultRecordUpdates = True grava, mais grava tudo repetido o que foi feito por ultimo na tabela filho.

Alguma outra idéia pessoal?


Responder
Bom pra quem puder me ajudar vou postar as tabelas relacionadas
Tabela mestre é esta aqui
CREATE TABLE DEAR (
    ID_DEAR            INTEGER NOT NULL,
    GERAR_CHAVE        VARCHAR(12) NOT NULL,
    NOM_SEGUR          VARCHAR(60) NOT NULL,
    SEXO               CHAR(1),
    APELIDO            VARCHAR(30),
    DT_NASCIMENTO      DATE NOT NULL,
    RG_SEGUR           VARCHAR(35),
    CPF_SEGUR          VARCHAR(14) NOT NULL,
    EST_CIVIL          VARCHAR(30),
    END_SEGUR          VARCHAR(65),
    BAIRRO             VARCHAR(50),
    MINICIPIO          VARCHAR(50),
    UF                 CHAR(2),
    TE_SEGUR           VARCHAR(30),
    CTPS_SEGUR         VARCHAR(25),
    PONTO_REF          VARCHAR(35),
    CONFRONTANTES      BLOB SUB_TYPE 1 SEGMENT SIZE 80,
    MATRICULA          VARCHAR(10),
    DATA_MATRICULA     DATE,
    PROF_ATUAL         VARCHAR(40),
    CAT_TRAB           VARCHAR(40),
    REG_INDIVIDUAL     CHAR(1),
    REG_ECON_FAMILIAR  CHAR(1),
    TIPO_CULTIVO       BLOB SUB_TYPE 1 SEGMENT SIZE 80,
    PROD_CULTIVADOS    BLOB SUB_TYPE 1 SEGMENT SIZE 80,
    ANEXO              BLOB SUB_TYPE 1 SEGMENT SIZE 80,
    TESTEMUNHA_1       VARCHAR(60),
    TESTEMUNHA_2       VARCHAR(60),
    RG_TEST_1          VARCHAR(35),
    RG_TEST_2          VARCHAR(35),
    END_TEST_1         VARCHAR(50),
    END_TEST_2         VARCHAR(50),
    USUARIO            VARCHAR(40),
    DATA_EFETIVO       TIMESTAMP,
    AUDITORIA          BLOB SUB_TYPE 1 SEGMENT SIZE 80,
    CPF_TEST_1         VARCHAR(14),
    CPF_TEST_2         VARCHAR(14),
    STATUS             CHAR(1)
);


Na table Master
/******************************************************************************/
/****                             Primary Keys                             ****/
/******************************************************************************/

ALTER TABLE DEAR ADD CONSTRAINT PK_DEAR PRIMARY KEY (GERAR_CHAVE);


Tabela detalhe é esta aqui
CREATE TABLE TB_PROPRIETARIO (
    ID_PROPR         INTEGER NOT NULL,
    NOM_PROPR        VARCHAR(60),
    END_PROPR        VARCHAR(60),
    DATA_INI         DATE,
    DATA_FIM         DATE,
    CAT_TRABALHADOR  VARCHAR(60),
    ID_CHAVE         VARCHAR(12) NOT NULL,
    STATUS           CHAR(1)
);


Na table detail
/******************************************************************************/
/****                             Primary Keys                             ****/
/******************************************************************************/

ALTER TABLE TB_PROPRIETARIO ADD CONSTRAINT PK_TB_PROPRIETARIO PRIMARY KEY (ID_PROPR);


/******************************************************************************/
/****                             Foreign Keys                             ****/
/******************************************************************************/

ALTER TABLE TB_PROPRIETARIO ADD CONSTRAINT FK_TB_PROPRIETARIO_1 FOREIGN KEY (ID_CHAVE) REFERENCES DEAR (GERAR_CHAVE) ON DELETE CASCADE ON UPDATE CASCADE;


Fiz no onexit do edit assim para chamar a busca master/detail
procedure TfrmAltDEAR.maskAltContDearExit(Sender: TObject);
begin
  inherited;
  with cdsAltDEAR do //TABLE MASTER
  begin
    Close;
    Params[0].AsString := maskAltContDear.Text;
    Open;
    if not IsEmpty then
    begin
      maskAltContDear.Text := Params[0].AsString;
      with cdsAltTB_Proprietario do //TABLE DETAIL
      begin
        {:Select para atualizar a grid}
        Close;
        Params[1].AsString := maskAltContDear.Text;
        Open;
      end;
    {:muda o datasource para modo de edit}
    if cdsAltDEAR.State <> dsEdit then
       cdsAltDEAR.Edit;
    end
    else
    begin
      Dc_MessageDlg(´Nº do Controle: ´+maskAltContDear.Text+´ não encontrada.´+13+
                    ´Digite outro Nº do Controle no formato 9999/AAAA Ex:(0001/2008).´, mtInformation, [MbOk],0);
      maskAltContDear.SetFocus;
    end;
  end;
end;

Então após isso no onexit ele vai me trazer os dados da tabela mestre e detalhe também, no segundo tabsheet tenho alguns dbeditds que fazem parte da tabela detalhe aonde vai poder incluir/deletar e alterar os dados, mas ainda não terminei de atualizar na tabela mestre, então no final tem mais alguns buttons para atualizar o que estou fazendo tambem na table mestre e se no caso o usuario resolver Cancelar tudo, o que deve ser feito é retornar como estava antes no banco nas duas tabelas.

Estou usando DBExpress+SQLDataSet+DSProvider (Camada Servidor) e na camada Cliente estou usando SOAPConnection ou COMConnection que esta ligado no ConnectionBroker que faz ligações com os ClientDataSet´s

Eu renomeei o ConnectionBroker para ConInternetLocal

Estou tambem usando Firebird 2.0

Eu tinha resolvido de tirar o botão insert neste formulário e deixar apenas gravar, alterar e excluir

Mais se eu excluo sem aplicar o applyupdate ele exclui e novamente ele retorna
procedure TfrmAltDEAR.btnExcluirClick(Sender: TObject);
begin
//  inherited;
  if Dc_MessageDlg(´Deseja realmente excluir o registro,´+#13+´do DEAR - ´+
                    dsAltTB_Proprietario.DataSet.FieldByName(´Nom_Propr´).AsString+´?´,mtInformation,
      [mbYes,mbNo],0) = mrYes then
  begin
    if not dsAltTB_Proprietario.DataSet.Active then
      dsAltTB_Proprietario.DataSet.Open;
      try
        dsAltTB_Proprietario.DataSet.Delete;
        {:Passa para o banco os dados que estão em cache na tabela AltTab_Proprietario}
        //(dsAltTB_Proprietario.DataSet as TClientDataSet).ApplyUpdates(0);
        Dc_MessageDlg(´Dados excluídos com sucesso´, mtInformation, [mbOk],0);
        {:Atualiza a tabela AltTab_Proprietario}
        dsAltTB_Proprietario.DataSet.Close;
        dsAltTB_Proprietario.DataSet.Open;
        dsAltTB_Proprietario.DataSet.Refresh;
        {:Trata os botões no no modulo Propriedade}
        btnExcluir.Enabled  := True;
        btnAlterar.Enabled  := True;
        btnGravar.Enabled   := False;
        btnCancelar.Enabled := False;
      except
        on E:Exception do
        begin
          dc_MessageDlg(´Ocorreu um erro neste processo. ´ +1313 +´Erro gerado: ´+13+
          E.Message + #1313 + ´Todo o processo foi abortado!´, mtError, [mbOk],0);
          Abort;
          dsAltTB_Proprietario.DataSet.Cancel;
        end;
      end; //Final try/except
    end;
end;

Se eu aplico agora o applyupdate ele me mostra a mensagem de erro
[b:fb2e99ac58]´Update Affected mode than 1 record´[/b:fb2e99ac58] Se eu mudar no DSProvider para poAllowRecorsUpdates(Não me recordo o nome de cabeça, mais deve ser este mesmo) para TRUE salva sem erro, mais todos ficma igual ao ultimo que foi feiot alteração. Então tambem não funcionou.

Se eu colocar o applyupdates da tabela detail no AfterScroll da table master tambem da erro no onexit daquele edit que eu uso para mostrar os dados das tabelas master/detail. Ou seja bem no select do detail.

Então esta parte eu não consegui resolver, mais como disse na parte do Insert resolvi fazer um novo form só para Insert e usar uma tabela Temporaria para cadastrar os dados detail e só gravar no final. Assim se o usuario resolver abandonar a operação se desfaz caso contrário grava na tabela.
{:Grava os dados no banco}
  dm.ConInternetLocal.Open;
  try {:começo do trecho try/finally}
    if DSPadrao.DataSet.State in [dsEdit, dsInsert] then
      try {:começo do trecho try/except do bloco da tabela DEAR}
        if Label36.Caption = ´00000´ then
          raise Exception.Create(´Atenção! Não foi gerado o controle do DEAR´+13+
                                  ´Não vai ser gravado os dados.´)
        else
          DSPadrao.DataSet.FieldByName(´gerar_chave´).asString := Label36.Caption;
          DSPadrao.DataSet.Post;
          {:Grava na tabela DEAR os dados do ClientDataSet}
          (DSPadrao.DataSet as TClientDataSet).ApplyUpdates(0);
          DSPadrao.DataSet.Close; {:atualiza os dados.}
          DSPadrao.DataSet.Open;
          {Grava na tabela Proprietários}
          Bookmark := cdsPropTemp.GetBookmark; {:Ponteiro - alocar memória e atribuir um valor}
          cdsPropTemp.DisableControls; {:Desativar exibição de registros de dados que controla}
          try {:Abre o Bloco Try/Except ou seja Tente ou abre uma exceção}
            try {::Abre o Bloco Try/Finnaly ou seja Tente ou Finalmente}
              cdsPropTemp.First; {:Ir para o primeiro registro na tabela temporaria}
              while not cdsPropTemp.Eof do //Enquanto não for fim na tabela temporaria transfere
              begin
                {:Transferindo os dados para o banco}
                if not dm.cdsSPProp_DEAR.Active = True then
                dm.cdsSPProp_DEAR.Active := True;
                dm.cdsSPProp_DEAR.Append;
                dm.cdsSPProp_DEARNOM_PROPR.AsString       := cdsPropTempNomProp.AsString;
                dm.cdsSPProp_DEAREND_PROPR.AsString       := cdsPropTempEndProp.AsString;
                dm.cdsSPProp_DEARDATA_INI.Value           := cdsPropTempDataINI.Value;
                dm.cdsSPProp_DEARDATA_FIM.Value           := cdsPropTempDataFim.Value;
                dm.cdsSPProp_DEARCAT_TRABALHADOR.AsString := cdsPropTempCatTrab.AsString;
                dm.cdsSPProp_DEARID_CHAVE.AsString        := cdsPropTempid_chave.AsString;
                dm.cdsSPProp_DEAR.Post;
                cdsPropTemp.Next; {:Proximo dado da tabela temporaria}
              end; {:final do loop}
            finally {:Finalmente}
              cdsPropTemp.GotoBookmark(Bookmark);
              cdsPropTemp.EnableControls; {:Abre a exibição de registros de dados dos controles, se faz necessário ao final}
              cdsPropTemp.FreeBookmark(Bookmark);{:Limpa da memoria o ponteiro bookmark}
              if dm.IBTransaction1.Active = False then
                 dm.IBTransaction1.Active := True;
                 dm.IBTransaction1.Commit;
              {:Limpa toda tabela que esta em memoria}
              (dsPropTemp.DataSet as TClientDataSet).CancelUpdates;
              {:Fecha todos Botões}
               btnInsere.Enabled   := False;
               btnExcluir.Enabled  := False;
               btnAlterar.Enabled  := False;
               btnGravar.Enabled   := False;
               btnCancelar.Enabled := False;
               b_first.Enabled := False;
               b_prior.Enabled := False;
               b_next.Enabled  := False;
               b_last.Enabled  := False;
            end; {:Final do bloco try/finally da tabela proprietario}
          except
              raise Exception.Create(´Problemas na transação dos dados, o processo não foi incluído no banco.´);
              Exit;
          end; {:Final do bloco try/except da tabela proprietário}
          Dc_MessageDlg(´Dados gravados com sucesso´, mtInformation, [mbOk],0);
      except
         on E:Exception do
         begin
           dc_MessageDlg(´Ocorreu um erro neste processo. ´ +#1313 +´Erro gerado: ´+13+
           E.Message + 1313 + ´Todo o processo foi abortado!´, mtError, [mbOk],0);
           Exit;
           DSPadrao.DataSet.Cancel;
           dm.IBTransaction1.Rollback;
         end;
      end; {:Final try/except da tabela DEAR}
  finally
     dm.ConInternetLocal.Close;
  end; {:final do trecho try/finally}
Assim funciona incluisve quero deixar desta forma, mais também se possivel fazer insert no form Alteração seria melhor ainda :D


Responder

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários. Para saber mais sobre o uso de cookies,
consulte nossa política de privacidade. Ao continuar navegando em nosso site, você concorda com a nossa política.

Aceitar