Exibir codigo após applyupdate

Delphi

08/07/2009

Oi pessoal,

estou usando o D7 com DBExpress e Firebird e tenho a seguinte SQL no SQLDataset:

SELECT * FROM CLIENTES WHERE CODIGO = :CODIGO

a tabela CLIENTES tem o campo CODIGO q é autonumeração

tudo está funcionando perfeitamente só q quando mando gravar, o código não é mostrado no dbtext, e se dou um refresh, devido ao parametro não é exibido nenhum registro.

quando não trabalho com parametro, posso usar o bookmark, mas, assim, não sei como fazer.

alguém pode me dar uma dica?


Fajo

Fajo

Curtidas 0

Respostas

.lg.

.lg.

08/07/2009

Teria como você postar o codigo de sua unit para facilitar a ajuda!? Se for muito grande.. (500, 1000, 2000 linhas) poste somente o código do seu post.
Ahh... lembre-se de postar os SELECTs que vc tá usando para a inserção.

Ps.:´Por favor use [b:af225b1962][[/b:af225b1962][b:af225b1962]Code[/b:af225b1962][b:af225b1962]]...seu codigo....[[/b:af225b1962][b:af225b1962]/Code[/b:af225b1962][b:af225b1962]][/b:af225b1962]´


GOSTEI 0
Fajo

Fajo

08/07/2009

.lg. cara é seguinte, tenho um form q representa a tabela de cadastro de clientes, com um dbnavigator e um botão com o código tbclientes.Applyupdate(0);
a query contem a seguinte SQL:
SELECT * FROM CLIENTES WHERE CODIGO = :CODIGO

ou seja, só vai abrir um registro por vez.

no form tenho:
um dbtext para o campo codigo
um dbedit para o campo nome

quando clico no botão gravar ele grava normalmente, só q o código, q é gerado automaticment pelo banco não aparece imediatamente, e eu gostaria de saber como fazer para q ele seja exibido assim q clicar no botão gravar.


GOSTEI 0
Marcos.gandin

Marcos.gandin

08/07/2009

O que você pode fazer é buscar o último código inserido e mostrar no campo código com o select abaixo:

SELECT MAX(CODIGO) AS CODIGO FROM CLIENTES

Ou seja, você grava o código e já em seguida busca o maior código inserido, que vai ser o código gerado e mostra no campo código.


GOSTEI 0
Fajo

Fajo

08/07/2009

Mas marcos essa forma eu já uso quando escolho q o código seja gerada no próprio delphi, o problema está exatamente pq o código está sendo gerado no banco, é claro q se não encontrar uma solução, terei q desativar a autonumeração do banco e passar a utilizar essa solução, mas não é possível q não haja uma solução plausível para esse problema.


GOSTEI 0
Marcos.gandin

Marcos.gandin

08/07/2009

Mas pelo que entendi o código é gerado automaticamente e não através da query: SELECT MAX(CODIGO) + 1 FROM CLIENTES

Se for assim, por essa query é só mostrar o código gerado. O que eu sugeri foi:

SELECT MAX(CODIGO) AS CODIGO FROM CLIENTES

sem o +1.

Você pode continuar a usar a autonumeração sem problemas, só vai usar essa query pra pegar o código gerado e mostrar na tela.


GOSTEI 0
Fajo

Fajo

08/07/2009

Ok, entendi,

agora se o sistema estiver em rede, e tiver sendo feito 2 cadastros de clientes ao mesmo tempo em estações diferentes..., acho q não vai dar sempre certo.


GOSTEI 0
Lightshine

Lightshine

08/07/2009

Em que momento vc cria o código autonumeração? (antes de inserir, depois de inserir, antes de salvar...)

Uma ideia séria após criar o código vc salvar ele numa variavel, e após salvar as alterações fazer uma pesquisa pelo codigo que vc salvou na variavel e retornar os dados na tela.

Deu pra entender ou fui mto confusa?? rs

Lightshine


GOSTEI 0
Danielrsanches

Danielrsanches

08/07/2009

Ok, entendi, agora se o sistema estiver em rede, e tiver sendo feito 2 cadastros de clientes ao mesmo tempo em estações diferentes..., acho q não vai dar sempre certo.


olá fajo !!!

olha, eu tenho o mesmo problema que o seu, mas pelo jeito, é um negócio meio sem solução (pelo menos até hj não consegui resolver 100¬)...

a única coisa que fiz, foi fazer o que o nosso amigo marcos.gandin falou:

O que você pode fazer é buscar o último código inserido e mostrar no campo código com o select abaixo: SELECT MAX(CODIGO) AS CODIGO FROM CLIENTES Ou seja, você grava o código e já em seguida busca o maior código inserido, que vai ser o código gerado e mostra no campo código.


quanto ao que vc disse, e tem toda razão:

agora se o sistema estiver em rede, e tiver sendo feito 2 cadastros de clientes ao mesmo tempo em estações diferentes..., acho q não vai dar sempre certo.


uma solução, é vc gerar o código apenas na hora de salvar o registro. o único problema, é que vc não conseguirá exibir o código ao usuário enquanto vc insere o registro, sendo possível apenas após salvá-lo ...

outra solução, é, assim que vc for inserir um novo registro, vc gravá-lo e entrar em modo de edição... assim vc já estará com o código na mão... só terá que se atentar em excluir o registro caso o usuário cancela a inclusão ...


espero ter conseguido explicar minha idéia !!!


abraços !!!


GOSTEI 0
Fajo

Fajo

08/07/2009

Resultado:

se for pra exibir o código após o salvamento do registro, não deixe o banco responsável pela numeração do campo, faça pelo próprio Delphi.


GOSTEI 0
Discorpio

Discorpio

08/07/2009

Boa noite a todos.

Uma coisa que vocês precisam saber sobre DBExpress é que o método ApplyUpdates do componente TClientDataSet por si só não grava no banco físico. O que ApplyUpdate faz é criar um conjunto de registros em lote com as linhas inseridas e ou editadas chamado de Delta. O dados só serão gravados no banco físico após o acionamento do método Commit do TSQLConnection, pois o Commit faz o TDataSetProvider apanhar os dados no Delta e fazer a atualização linha a linha.

Outra coisa é que o DBExpress trabalha com registros desconectados, ou seja, os componentes unidirecionais que são TSQLDataSet, TSQLTable e o TSQuery e até mesmo o TSQLStoredProc, apanham os registros no banco físico de dados através de uma transação e os enviam para o TDataSetProvider que monta o cursor de dados no TClientDataSet fazendo um cache local no HD, e despois fecha a transação se desconectando do banco.

Assim sendo, para fazer o que você pretende, ou seja, a autoincremento tem que se mesmo na aplicação Delphi, e não no banco, e este auto-incremento tem que ser realizado de preferência no momento da Inserção de dados no cache local do hd, ou seja, no TClientDataSet.

Mas como vou saber qual o último registro, se ele está lá no banco físico :?:

Simples, voce vai usar um componente TSQLQuery somente linkado ao TSQLConnection, não link ele com nenhum TDataSetProvider e nem TClienteDataSet, apenas para apanhar o código do último registro e somar mais um, e com a instrução SQL da dica do nosso amigo Marcos.Gandin, só que desta forma:

  Select (Max(Codigo) + 1) as Ultimo From Clientes


Repare que dentro do SQL eu já faço o autoincremento.

Como o TSQLQuery abre a transação, apanha o último código e já o incrementa, isto significa dizer que este autoincremento já está dentro da sua aplicação, bastando tão somente associar ele a campo Codigo no TClientDataSet, tudo isso sendo feito no momento de inserção do registro no TClientDataSet, no evento OnNewRecord, assim:

procedure TForm1.ClientDataSet1NewRecord(DataSet: TDataSet);
begin
  SQLQuery1.Open;
  if SQLQueryUltimo.isNull then
     ClientDataSet1Codigo.asInteger := 1
  else
     ClientDataSet1Codigo.asInteger := SQLQuery1Utimo.asInteger;
  SQLQuery1.Close;  
end;


Assim eu mato dois coelhos com um cajadada só, ou seja, vou a banco de dados, apanho o último registro e o incremento, associo o valor ao campo código do ClientDataSet no momento da Inserção de dados, quando faço isso, qualquer componente que liga a dados que estiver linkado a ClientDataSet e o campo código, ele ficará visível, voce fica sabendo qual o último registro já no momento da Inserção de dados no ClientDataSet.

A outra cajada é que se eu cancelar a inserção de registro, esse autoincremento não será enviada ao banco físico, que repito mais uma vez, só será possível com o acionamento do método Commit do SQLConnection.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

08/07/2009

Discorpio, e no caso de o sistema rodar em rede? Não corre o risco de haver duplicidade de códigos?


GOSTEI 0
Lightshine

Lightshine

08/07/2009

Executa a Trigger no evento Before Insert da tabela e no evento After Insert recupere o código gerado assim:

SELECT GEN_ID(<nome_generator>, 0) FROM RDB$DATABASE

Lightshine.


GOSTEI 0
Lightshine

Lightshine

08/07/2009

Ah! Exqueci de falar...

Você pode usar esta forma de obter o valor do autoincremento caso no seu sistema utilize a dobradinha Generator/Trigger para gerar este codigo.

Lightshine


GOSTEI 0
Discorpio

Discorpio

08/07/2009

Bom dia a todos

Discorpio, e no caso de o sistema rodar em rede? Não corre o risco de haver duplicidade de códigos?


Emerson

Neste caso, sim, voce corre o risco de ter registro duplicados em rede, o exemplo que eu dei era para monousuário.

Já em caso de redes, ao se criar uma Trigger no Banco, toda vez que voce inserir um registro voce terá que autoincrementar no banco, só que não devemos esquecer, que quando voce faz inserções com o método Insert ou Append, voce o está fazendo no momento, no TClientDataSet, ou seja, no cache de HD, e não no banco físico. Outro detalhe também é que ao fazer a inserção no TClientDataSet, ele não vai deixar fazer a inserção nele (cache de HD) sem que haja um valor para o código, valor este que não pode ser duplicado, isto porque o TClientDataSet, ao ter os seus registros carregados pelo TDataSetProvider, este também o carregou o MetaData da tabela cujo campo Codigo está configurado como ´Not Null´.

Mas como resolver esta caso então :?:

Adotaremos então a dica do nosso amigo Lightshine, só que com uma diferença, ao invés de se criar a Trigger no banco de dados, crie somente o Generator, e o código que ele postou, voce vai colocar dentro do propriedade SQL do TSQLQuery lá na dica que mencionei, assim:

  Select Gen_ID(<Nome_Generator>,1) as Ultimo From RDB$Database


Agora outro detalhe que não devemos de mencionar, é que com o Generator, corremos o risco de se o usuário cancelar a inserção, de fazemos um autoincremento que não será usado, e o valor autoincrementado ficar orfão no banco físico.

Neste caso, ao invés de usar o evento OnNewRecord, usaremos então o evento OnBeforeInsert do TClientDataSet, assim:

  procedure TDM.ClientDataSet1BeforeInsert(DataSet: TDataSet);
  begin
     SQLQuery1.Open;
     ClientDataSet1Codigo.asInteger := SQLQuery1Utimo.asInteger;
     SQLQuery1.Close;  
  end;


Com o código acima haverá apenas uma diferença, voce autoincrementa diretamente no Banco e não mais na Aplicação e continua fornecendo o valor ao campo código do TCLientDataSet, e ao mesmo tempo recuperando o seu valor autoincrementado.

Mas o porque de não criar a Trigger :?:

Simples, ela só vai ser disparada quando o método Commit do SQLConnection for acionado, e neste caso, o campo código já terá que estar com o seu valor autoincrementado.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

08/07/2009

Bom dia a todos [quote:f24d4d06b4=´emerson.en´]Discorpio, e no caso de o sistema rodar em rede? Não corre o risco de haver duplicidade de códigos?

Adotaremos então a dica do nosso amigo Lightshine, só que com uma diferença, ao invés de se criar a Trigger no banco de dados, crie somente o Generator, e o código que ele postou, voce vai colocar dentro do propriedade SQL do TSQLQuery lá na dica que mencionei, assim:

  Select Gen_ID(<Nome_Generator>,1) as Ultimo From RDB$Database


Neste caso, ao invés de usar o evento OnNewRecord, usaremos então o evento OnBeforeInsert do TClientDataSet, assim:

  procedure TDM.ClientDataSet1BeforeInsert(DataSet: TDataSet);
  begin
     SQLQuery1.Open;
     ClientDataSet1Codigo.asInteger := SQLQuery1Utimo.asInteger;
     SQLQuery1.Close;  
  end;


Com o código acima haverá apenas uma diferença, voce autoincrementa diretamente no Banco e não mais na Aplicação e continua fornecendo o valor ao campo código do TCLientDataSet, e ao mesmo tempo recuperando o seu valor autoincrementado.

Mas o porque de não criar a Trigger :?:

Simples, ela só vai ser disparada quando o método Commit do SQLConnection for acionado, e neste caso, o campo código já terá que estar com o seu valor autoincrementado.[/quote:f24d4d06b4]

perfeito! só questionei porque achei que a sua primeira resposta não traria uma solução definitiva para o colega, podendo, inclusive, gerar um problema diferente do que ele já tinha.

quanto a afirmativa
Agora outro detalhe que não(???) devemos de mencionar, é que com o Generator, corremos o risco de se o usuário cancelar a inserção, de fazemos um autoincremento que não será usado, e o valor autoincrementado ficar orfão no banco físico.
isso nunca foi problema, visto que, na teoria, um campo autoincremento é um campo ´interno´, e também porque esse controle pode ser feito através do DatasetProvider, utilizando o evento BeforeUpdateRecord em conjunto com a opção PropagateChanges, evitando, assim, o código ´órfão´.


GOSTEI 0
Lightshine

Lightshine

08/07/2009

Discorpio,

Nosso amigo Lightshine??
Prefiro nossA amigA Lightshine rsrs Sou mulher !!!!
kkkkkkkkkkkkkkkkkkkkkkkkk

T+

Lightshine


GOSTEI 0
Discorpio

Discorpio

08/07/2009

Boa tarde a todos

Discorpio, Nosso amigo Lightshine?? Prefiro nossA amigA Lightshine rsrs Sou mulher !!!! kkkkkkkkkkkkkkkkkkkkkkkkk T+ Lightshine


Me desculpe Lightshine, mas não dá pra diferenciar o sexo só pelo codinome ´Brilho da Luz´

De qualquer forma te peço perdão.

Emerson. É por essa razão que eu particularmente não gosto de usar campos autoincrementos quando utilizo o DBExpress.

Em se tratando das tabela Cliente, por exemplo, se ele for pessoa jurídica, eu utilizo como chave primária o campo CNPJ e for pessoa física, eu utilizo o campo RG com chave primária.

Se a tabela for Produtos, utilizo o campo Modelo, ou número de série do produto, e se for Controle de Estoque, faço um gerador de código de controle de estoque, onde anexo o ano, tipo 0930/2009 em uma função que criei para os meus sistemas que só incrementa o número e anexa o ano da data do sistema na string.


GOSTEI 0
Lightshine

Lightshine

08/07/2009

Boa tarde a todos [quote:19b965ce77=´Lightshine´]Discorpio, Nosso amigo Lightshine?? Prefiro nossA amigA Lightshine rsrs Sou mulher !!!! kkkkkkkkkkkkkkkkkkkkkkkkk T+ Lightshine


Me desculpe Lightshine, mas não dá pra diferenciar o sexo só pelo codinome ´Brilho da Luz´

De qualquer forma te peço perdão.

[/quote:19b965ce77]

Discorpio,

Fica tranquilo, esse nick é mesmo bem unisex, já acostumei ^^
Não precisa pedir perdão, eu brinquei só para descontrair um pouco hehe

T+

Lightshine


GOSTEI 0
POSTAR