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