Campo Auto-incremento Firebird/Interbase

 

Salve amigos.

Sempre que visito fóruns, salas de bate papo e outras relacionadas a programação em Delphi, vejo que uma das dúvidas mais comuns é como projetar um bom sistema, e automático, de chave auto-incremento no Firebird/Interbase. Já vi muita coisa e acho que uma das soluções que eu adotei é bem produtiva e muito eficiente. O conceito não é novo mas eu nunca vi assim como vou propor.

Bom um dos primeiros passos para um bom sistema é uma boa padronização do BD. Toda a nomenclatura dos meus BD eu padronizo. Uma delas, é que mais nos interessa: o generator. O meu é formado da seguinte maneira (sempre) "GEN_[tabela]_ID". Seguindo esse mesmo conceito eu também padronizo a nomenclatura dos meus objetos no Delphi. SQLQuery = qryTABELA, DataSetProvider = dspTABELA, ClientDataSet = cdsTABELA. Eu também acho muito mais produtivo separar os DMs dessa forma: um RDM onde vai ficar as Queries e os DataSetProviders, assim facilmente poderemos "transformar" nossa aplicação CS em Multi-Tier, e um DM onde ficam os CDSs. Como a propriedade ProviderName do CDS é uma string ele não vai "ver" os DSP do RDM, assim colocamos o componente TLocalConnection no RDM em um TConnectionBroker no DM e apontamos sua propriedade Connection para o RDM->TLocalConnection. De posse dessas informações podemos prosseguir.

No RDM onde estão todos os DSP, aponte BeforeUpdateRecord de todos os DSP para o mesmo evento.

Essa é a assinatura do evento:

 

BeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet;

  DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind;

  var Applied: Boolean);

 

E no evento codifique assim:

Crie uma variável Campo do tipo TField e uma variável SQLStmt do tipo String e tbm uma variável Tabela do tipo String e por fim uma variável CustomSQLDataSet do tipo TCustomSQLDataSet. Não se esqueça de declarar e unit DB.

 

case UpdateKind of

ukInsert: // Inserindo um registro

  begin

    Campo := DeltaDS.Fields[0];

    if (Campo.DataType = ftInteger) and Campo.IsNull then

    begin

      Tabela  := UpperCase(IProviderSupport(SourceDS).PSGetTableName);

      SQLStmt := Format(SELECT GEN_ID(GEN_%s_ID, 1) FROM RDB$DATABASE, [Tabela]);

      SQLCon.Execute(SQLStmt, nil, @CustomSQLDataSet);

      if Assigned(CustomSQLDataSet) then

      begin

        DeltaDS.Edit;

        Campo.NewValue := CustomSQLDataSet.Fields[0].AsInteger;

        DeltaDS.Post;

        SysUtils.FreeAndNil(CustomSQLDataSet);

      end;

    end;

  end;

 

Veja que em SQLStmt existe GEN_%s_ID, por isso eu uso um padrão de nomenclatura para os meus Generators no banco. Primeiro ele verifica se o campo[0], que eu sempre deixo a primary key, é do tipo Inteiro e se está nulo, porque eu posso ter atribuído o valor da chave antes, num caso em que vc tem Pedido e Ítens de Pedido, o valor da chave tem que ser atribuido antes, depois executo o SQLStmt apontando o ResultSet, que é um ponteiro, para o CustomSQLDataSet.

Se a pesquisa retornar dados o CustomSQLDataSet vai ter o valor do generator incrementado, aí é só atribuir o valor para o Delta.

Pronto, sua aplicação ja tem um campo auto-incremento totalmente automatizado !

Um abraço e até a próxima