Fórum Auto incremento com sum max? #424061
19/09/2012
0
Eu gostaria de saber a melhor maneira de implementar um auto incremento no Firebird.
Eu estou fazendo ate o momento com Generators. Estou fazendo alguns testes e não gostei muito.
Quando tento gravar no banco e da algum erro mesmo assim ele gera um novo numero, isso faz com que eu fique
com buracos na numeração do meu banco.
No delphi eu uso o seguinte Código no evento BeforeUpdate Record do DataSetProvider.
if UpdateKind = ukInsert then
begin
if SourceDs = sdsCor then
begin
sdsGenCor.Open;
try
id := sdsGenCor.FieldByName('NOVOID').AsInteger;
finally
sdsGenCor.Close;
end;
DeltaDs.FieldByName('CODI_COR').NewValue :=id;
end;
end;
end;onde id é uma variavel que recebe valor 0 na criação do datamodule e é decrementada para passar o valor para o
campo chave da tabela.
Eu tava querendo implementar alguma coisa com select max no evento AfterPost do ClientDataSet.
Queria fazer tipo pra gerar um novo valor só se nao der nem um erro no ApplyUpdates e se todos os campos obrigatorios
estiverem preenchidos ai sim gera o codigo.
So não estou sabendo montar essa instrução.
Alguem tem alguma ideia?
Um exemplo pra me passar?
Eu não quero é deixar furos na numeração.
Willian Amor
Curtir tópico
+ 0Posts
19/09/2012
Alisson Santos
Gostei + 0
19/09/2012
Deivison Melo
Ou ainda pode utilizar a função abaixo:
function GeneratorID (aName: string; Connection: TSQLConnection;
Incrementa: Boolean): integer;
var
Qry: TSQLQuery;
begin
Qry := TSQLQuery.Create(nil);
try
Qry.SQLConnection := Connection;
if Incrementa then
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 1) FROM RDB$DATABASE')
else
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 0) FROM RDB$DATABASE');
Qry.Open;
Result := Qry.Fields[0].AsInteger;
finally
FreeAndNil(Qry);
end;
end;
Gostei + 0
19/09/2012
Claudia Nogueira
Tem um artigo meu publicado no firebase sobre esse assunto e espero que seja útil.
Qualquer dúvida pode perguntar.
http://www.firebase.com.br/fb/artigo.php?id=2396
Gostei + 0
20/09/2012
Willian Amor
quero uma maneira onde não gere um numero se der erro antes de gravar.
Que so gere um novo valor se realmente o registro for gravado no banco.
Gostei + 0
20/09/2012
Willian Amor
Tem um artigo meu publicado no firebase sobre esse assunto e espero que seja útil.
Qualquer dúvida pode perguntar.
http://www.firebase.com.br/fb/artigo.php?id=2396
Eu ja havia tentado assim também, porém se der erro na hora de gravação ainda sim ele gera um novo número,
tipo inicializa em zero, o generator ganha o valor 1 e da erro na gravação. Depois se eu for na tabela ela nao tera o
valor 1 ja vai pular para o 2.
Incrementa: Boolean): integer;
var
Qry: TSQLQuery;
begin
Qry := TSQLQuery.Create(nil);
try
Qry.SQLConnection := Connection;
if Incrementa then
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 1) FROM RDB$DATABASE')
else
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 0) FROM RDB$DATABASE');
Qry.Open;
Result := Qry.Fields[0].AsInteger;
finally
FreeAndNil(Qry);
end;
end;
Eu estava querendo montar o seguinte, uma função realmente.
Por exemplo eu tenho uma função que verifica se os campos obrigatorios foram quando o usuario clica em salvar.
Se foram ele grava, do contrario avisa ao usuario que o campo "TAL" deve ser informado.
O problema é assim. Se passar por essa função mas se der erro no ApplyUpdates(<> 0), ele retorno um erro,
e da maneira como estou fazendo hoje, mesmo dando erro no ApplyUpdates ele gera um novo numero para o Generator,
ai eu perco um numero, fica um furo no meu banco. Eu queria ver se consigo montar algo no beforePost onde
eu ia verificar se ApplyUpdates (= 0) e se os campos obrigatorios foram preenchidos.
Se passar por essas informações ai sim geraria um novo codigo.
Alguem pode me dar uma ideia?
Gostei + 0
20/09/2012
Claudia Nogueira
Exemplo:
Var
iCodigo : Integer;
begin
try
IBQuery1.Close;
IBQuery1.SQL.Text := 'INSERT INTO cidade (id_cidade, nome_cidade, uf) VALUES (0, :nome, :uf)';
IBQuery1.ParamByName('nome').AsString := 'SÃO PAULO';
IBQuery1.ParamByName('uf').AsString := 'SP';
IBQuery1.ExecSQL;
iCodigo := 0;
IBQuery1.Close;
IBQuery1.SQL.Text := 'SELECT GEN_ID(GEN_ID_CIDADE, 0) codigo FROM RDB$DATABASE';
IBQuery1.Open;
if not IBQuery1.IsEmpty then
iCodigo := IBQuery1.FieldByName('codigo').AsInteger;
IBTransaction1.CommitRetaining;
except
IBTransaction1.RollbackRetaining;
end;
end;
Coloquei aquele iCodigo recebendo o valor do último generator para caso você esteja querendo fazer várias operações, e as inserções subsequentes estiverem ligadas por uma chave com a primeira tabela.
Gostei + 0
20/09/2012
Alisson Santos
Geralmente eu faço rotina direto no provide dataset abortando o processo.
Gostei + 0
21/09/2012
Willian Amor
Exemplo:
Var
iCodigo : Integer;
begin
try
IBQuery1.Close;
IBQuery1.SQL.Text := 'INSERT INTO cidade (id_cidade, nome_cidade, uf) VALUES (0, :nome, :uf)';
IBQuery1.ParamByName('nome').AsString := 'SÃO PAULO';
IBQuery1.ParamByName('uf').AsString := 'SP';
IBQuery1.ExecSQL;
iCodigo := 0;
IBQuery1.Close;
IBQuery1.SQL.Text := 'SELECT GEN_ID(GEN_ID_CIDADE, 0) codigo FROM RDB$DATABASE';
IBQuery1.Open;
if not IBQuery1.IsEmpty then
iCodigo := IBQuery1.FieldByName('codigo').AsInteger;
IBTransaction1.CommitRetaining;
except
IBTransaction1.RollbackRetaining;
end;
end;
Coloquei aquele iCodigo recebendo o valor do último generator para caso você esteja querendo fazer várias operações, e as inserções subsequentes estiverem ligadas por uma chave com a primeira tabela.
Eu to usando DBExpress.Eu achei que o Provider já cuidava da transação.
Geralmente eu faço rotina direto no provide dataset abortando o processo.
Posso tentar mas quando da erro de Applyupdates ele nao grava nada. Ja aborta a transação. Mas como ele fez a tentativa
de mandar os dados para o banco já gerou um novo numero para o generator.
Gostei + 0
24/09/2012
Willian Amor
inicialei uma variavel na criação do meu datamodule e no onnewrecord do ClientDataSet eu a decremento para 0.
entao no beforepost do CDS eu verifico se ele for menor que 1 executa o select max, se nao ele deixa o numero que ja está la.
Obrigado a todos....
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)