11/09/2004

Mestre/detalhe com DBExpress

FAla galera...
É o seguinte: eu to fazendo aki uma aplicação e nela tenho a parte de vendas, q eh mestre detalhe: Tenho o clientdataset, o sqladataset e o dataset provider para a tabela vendas e os mesmos componentes para a tabela itens, configurados para uma relação mestre/detalhe.
O problema surge quando eu vou adicionar uma venda. Quem numera a venda (auto inc) é o banco e esse número não é retornado imediatamente para a aplicação. Abro a transação e gravo a venda, ,ate ai tudo bem, so q quando vou adicionar os items da venda a coisa complica pq eles não são salvos com o id da venda....
Isso não acontece se eu salvar a venda, dar um refresh, localizar a venda que acabei de cadastrar e depois adicionar os itens. Se eu fizer assim da certim... Alguem tem alguma sugestão de como fazer para abrir a transação, salvar a venda, adicionar itens e so dar um commit depois dos itens adicionados, ou de pelo menos um item adicionado mantendo assim a consistência de dados?

Espero ter sido claro...
Obrigado


Wart

Respostas

11/09/2004

Vinicius2k

Colega,

Em casos como estes é conveniente que vc não deixe o banco fazer a auto-numeração através da Trigger, mas não abra mão dos generators pois são muito mais seguros do que outros métodos...
1. Execute uma query auxiliar com seguinte instrução :
select GEN_ID(Nome_do_Generator,1) from RDB$DATABASE

e leia o TField ´GEN_ID´ que é do tipo Integer, e atribua seu valor ao seu campo que seria auto-numerado, este procedimento deve ser realizado no BeforePost do ClientDataSet por exemplo...

2. Ajuste sua Trigger para que ela só auto-numere o campo se ele não contiver valor, ou simplesmente drope-a :
CREATE TRIGGER NOME_DA_TRIGGER FOR NOME_DA_TABELA
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
  IF (NEW.NOME_DO_CAMPO IS NULL) THEN
    NEW.NOME_DO_CAMPO = GEN_ID(NOME_DO_GENERATOR,1);
END
^

Particularmente, todas as minhas triggers de auto-numeração tem este formato, e aonde eu acho mais conveniente ou necessário, quem faz a autonumeração é a aplicação através do passo 1.

Vc pode utilizar uma função para automatizar este processo, algo como :
function TDataModule.NovaID(GenName: String): Integer;
var DataSet: TSQLDataSet;
begin
  Result:= 0;
  DataSet:= TSQLDataSet.Create(nil)  
  with DataSet do
    begin
      SQLConnection:= Nome_da_SQLConnection;
      CommandText:= select GEN_ID(´+ GenName + ´,1) from RDB$DATABASE´;
      try
        Open;
        Result:= FieldByName(´GEN_ID´).AsInteger
      finally
        Free;
      end;
    end;
end;

Vc pode declarar o cabeçalho desta função na seção PUBLIC do DataModule e vc terá ela disponível em todos os forms que tem o DataModule na lista de uses...
function NovaID(GenName: String): Integer;

Antes de efetuar a gravação do registro mestre, chame :
Nome_do_ClientDataSet.FieldByName(´NOME_DO_CAMPO´).AsInteger:= NovaID(´Nome_do_Generator´);

Acho q vai resolver seu problema, mas vc precisa observar 1 ponto, normal, mas para q vc não esteja desavisado :
-> Uma vez chamada a função GEN_ID, seja por query ou pela função de automação, vc teve o retorno e o generator no banco já foi incrementado. Se o usuário cancelar a operação ou a transação de inserção, por algum motivo falhar (com relação a transação poderia ocorrer também, mesmo usando a trigger), este número será ´perdido´...

Espero ter ajudado...
T+


Responder Citar

11/09/2004

Wart

Colega,
Quanto ao ponto que você citou eu estou ciente e agradeço muito a sua ajuda, vai ser extremamente útil. :wink:

Brigadão novamente e até a próxima...


Responder Citar