DataSet: Como mover o cursor para o registro recém inserido?
Toda vez que você insere um registro (Insert/ApplyUpdate) o cursor move para o inicio, como move-lo para o registro recém inserido?
Ps: não posso usar clientdataset.last; pois os dados usam uma query order by, então o registro novo não é necessáriamente o último na ordem do DataSet.
Ps: não posso usar clientdataset.last; pois os dados usam uma query order by, então o registro novo não é necessáriamente o último na ordem do DataSet.
Joeyramone
Curtidas 0
Respostas
Paullsoftware
19/09/2008
Normalmente não uso Grid para inserção de dados diretamente, mais talvez você resolva o seu problema guardando o Codigo do registro inserido depois dando um locate para localizar o respectivo codigo... :wink:
GOSTEI 0
Joeyramone
19/09/2008
Inicialmente o que eu quero é justamente pegar o código/primary key do registro inserido , por isso preciso mover o cursor para tal registro, aliás é só por isso que o insiro e aplico o update e só depois o edito como no código que vou mostrar.É um generator então só da para pegar depois de inserido e não posso me basear pelo valor mais alto anterior pois em um ambiente multi-usuário vai dar problema.
Eu fazia o seguinte quando o order by era ascendente e pelo generator:
Mas como o order by agora é por outro campo, isso não funciona mais. o novo registro pode aparecer em qualquer parte...
Eu fazia o seguinte quando o order by era ascendente e pelo generator:
ClientDataSet1.Insert; ClientDataSet1.ApplyUpdates(0); ClientDataSet1.Refresh; ClientDataSet1.Last; // Aqui o cursor estava no registro criado e podia então pegar a primary key ClientDataSet1.Edit; // E em seguida editar o registro coisa que também preciso na sequência
Mas como o order by agora é por outro campo, isso não funciona mais. o novo registro pode aparecer em qualquer parte...
GOSTEI 0
Rogerioluz
19/09/2008
Qual o banco e qual a versão. Se for Firebird 2.0 você pode usar o parâmetro Return e até inserir numa messagedlg (se estiver usando o Delphi).
O Parâmetro é usao em store Procedures.
Um Abraço...
Rogério Luz
O Parâmetro é usao em store Procedures.
Um Abraço...
Rogério Luz
GOSTEI 0
Joeyramone
19/09/2008
Estou usando justamente o firebird 2. Pode me explicar melhor isso ai e dar um exemplo? Valeu.
GOSTEI 0
Marco Salles
19/09/2008
Mas seria bom vc tentar explicar pq necessita do código/primary key do registro inserido ... Por acso seria por causa de Algum Relacionamento ??
É bom pensar nisso pq vc diz que :
´insiro e aplico o update e só depois o edito como no código que vou mostrar´ mas tb vc tem um incoveniente que é o fato de estar trabalhando em um ambiente multi-usuário.
Logo Aplicar Update apos cada inserção vc terá uma queda de performance muito grande
eu não sei se o BookMark ira funcionar com a Estrutura OrderBy, Acredito que sim... Logo seria melhor Guardar a Posição usando a StringOpaca. Isto ate guarda a Posição do Registro, mas o Updates
a cada Inserção continuo sem entender ???
É bom pensar nisso pq vc diz que :
´insiro e aplico o update e só depois o edito como no código que vou mostrar´ mas tb vc tem um incoveniente que é o fato de estar trabalhando em um ambiente multi-usuário.
Logo Aplicar Update apos cada inserção vc terá uma queda de performance muito grande
eu não sei se o BookMark ira funcionar com a Estrutura OrderBy, Acredito que sim... Logo seria melhor Guardar a Posição usando a StringOpaca. Isto ate guarda a Posição do Registro, mas o Updates
a cada Inserção continuo sem entender ???
GOSTEI 0
Luciano.lirio
19/09/2008
JoeyRamone,
montei um exemplo usando o ClientDataSet retornando um ID no link abaixo.
[url]www.mattos.eti.br/ClientDataSet.zip[/url]
pesquer te ajudar.
Att,
montei um exemplo usando o ClientDataSet retornando um ID no link abaixo.
[url]www.mattos.eti.br/ClientDataSet.zip[/url]
pesquer te ajudar.
Att,
GOSTEI 0
Luciano.lirio
19/09/2008
usei select @@identity que é para o SQL Server e o Access, para o FireBird acho que é o SELECT GEN_ID(nome do generator,1) FROM RDB$DATABASE.
Att,
Att,
GOSTEI 0
Joeyramone
19/09/2008
Luciano, ajudou a principio, o código funciona, mas no meu caso especifico eu uso DBExpress/SqlDataSet e estou recebendo erros de campos não encontrados ao fazer este SELECT(os demais campos que não são o Generator.
Marcos, já tentei o bookmark, não funciona, quanto ao ApplyUpdates eu que não entendi, qual seria o seu procedimento??
Eu sempre fiz assim:
-ClienteDataset.MODO(Insert,Edit etc)
-faço oq tem q ser feito
-ApplyUpdates;
-Refresh;
Marcos, já tentei o bookmark, não funciona, quanto ao ApplyUpdates eu que não entendi, qual seria o seu procedimento??
Eu sempre fiz assim:
-ClienteDataset.MODO(Insert,Edit etc)
-faço oq tem q ser feito
-ApplyUpdates;
-Refresh;
GOSTEI 0
Marco Salles
19/09/2008
Marcos, já tentei o bookmark, não funciona, quanto ao ApplyUpdates eu que não entendi, qual seria o seu procedimento??
Eu sempre fiz assim:
-ClienteDataset.MODO(Insert,Edit etc)
-faço oq tem q ser feito
-ApplyUpdates;
-Refresh;
Desse modo , em ambiente de rede não é recomendado. Vc a cada Insert/Edit Trafega Dados na Rede.
O certo é fazer Tudo o que tem que ser feito <Varias Inserções, Varrios Edits> e no fim dar o Applyupdates. Assim os Dados são empacotados e enviados no mesmo Pacote
estou recebendo erros de campos não encontrados ao fazer este SELECT
Vc deve estar Usando o memso SqlQuery ou ClientDataSet para Fazer o Select , e ´eles´ Devem estar com os Fileds Definidos. Ou Talves oS Fileds
estão como Requeridos Logo na Montagem do Sql irá Reclamar
Geralmente neste tipo de problema uma Boa Prática de Programação
é o Uso de uma Função Genérica: Tipo esta
{O parâmetro TableName indica o nome da tabela da qual deseja-se
pegar o valor do generator que está associado a ela, sendo
que os generators criados no banco devem seguir o padrão
GEN_NomeTable_ID. Caso os generators do seu banco
não estejam neste padrão, altere o código desta função
para o formato do nome do seu generator. O nome do generator
poderia ser passado via parâmetro, ao invés de o nome
da tabela, porém, fica mais fácil simplesmente passar
o nome da tabela e a função montrar o nome do generator
a partir daí. Assim, o desenvolvedor não precisa
ficar pensando em como é o formato do nome
dos generators.
O parâmetro Incremento é um parâmetro Default. Se ele
for omitido na chamada da função, seu valor será 1.
Este valor indica que, antes de retornar o valor do generator,
este é incrementado com o valor do parâmetro Incremento, e é retornado
o valor do generator depois de incrementado. Se Incremento for passado
como zero, a função apenas devolve o valor atual do generator, sem
incremetá-lo.}function TSeuDataModulo.PrimaryKeyValue(TableName: ShortString;
Incremento: Byte): Integer;
var
dts: TSQLDataSet;
begin
//Cria um objeto local da classe TSQLDataSet
dts:= TSQLDataSet.Create(nil);
try
//Associa o dts à conexão SQLConnection1
dts.SQLConnection := SQLConnection1;
{gera um select para pegar o valor do generator
associado à tabela informado em TableName.
A tabela rdb$database é uma tabela de sistema, ou seja,
uma tabela interna do Firebird. Ela está sendo utilizada aqui
para executar selects que não trazem dados de nenhuma
tabela criada pelo desenvolvedor, e sim para executar
a função gen_id do Firebird. Como no Firebird, e em muitos outros bancos,
todo select deve possuir um "from NOME_TABELA"
(diferente do Microsoft SQL Server), então é usada
esta tabela interna do Firebird que sempre retorna apenas um registro
e permite a execuçã de função como gen_id, current_date, current_time, etc.}
dts.CommandText :=
´select gen_id(GEN_´ +
TableName + ´_ID, ´+IntToStr(Incremento)+´) from rdb$database´;
dts.Open;
//Pega o valor do generator
result:= dts.Fields[0].AsInteger;
dts.Close;
finally
dts.Free;
end;
end;Agora no Evento AfterInsert dos seu Cds voce coloque o Codigo
DataSet[´Seu_ID´]:=SeuDataModulo.PrimaryKeyValue(´NomeDaSuaTabela´)
GOSTEI 0
Paullsoftware
19/09/2008
vamos por parte...
como você está fazendo pra gerar o novo ID da tabela?
no evento AffterInsert do seu cds coloque:
no evento AffterPost faça...
não sei vai funcionar é só uma ideia, nos passe mais detalhes de como está fazendo, como ta gerando a ID da tabela etc.. :wink:
como você está fazendo pra gerar o novo ID da tabela?
no evento AffterInsert do seu cds coloque:
variavelglobal_do_tipo_iteiro:=0;
no evento AffterPost faça...
if TClientDataSet(DataSet).ApplyUpDates(0)<=0 then
begin
TClientDAtaSet(DataSet).ApplyUpDates(-1);
variavelglobal_do_tipo_Inteiro := NomeDoCDSNomeDoCampoChave.AsInteger;
end;
DataSet.Locate(´NomeDoCampoChave´,Variavel_do_tipo_inteiro,[]);
não sei vai funcionar é só uma ideia, nos passe mais detalhes de como está fazendo, como ta gerando a ID da tabela etc.. :wink:
GOSTEI 0
Joeyramone
19/09/2008
Marco, fiz isso ae, agora foi, ta bonito...
Valeu ae tb paulo...
Valeu ae tb paulo...
GOSTEI 0
Paullsoftware
19/09/2008
[quote:165f1c69b1=´Marco Salles´]
Desse modo , em ambiente de rede não é recomendado. Vc a cada Insert/Edit Trafega Dados na Rede.
O certo é fazer Tudo o que tem que ser feito <Varias Inserções, Varrios Edits> e no fim dar o Applyupdates. Assim os Dados são empacotados e enviados no mesmo Pacote
Vc deve estar Usando o memso SqlQuery ou ClientDataSet para Fazer o Select , e ´eles´ Devem estar com os Fileds Definidos. Ou Talves oS Fileds
estão como Requeridos Logo na Montagem do Sql irá Reclamar
Geralmente neste tipo de problema uma Boa Prática de Programação
é o Uso de uma Função Genérica: Tipo esta
Agora no Evento AfterInsert dos seu Cds voce coloque o Codigo
[/quote:165f1c69b1]Marcos eu sempre disparo o gerador no evento [b:165f1c69b1]BeforedUpDateRecord[/b:165f1c69b1] do DataSetProvider, existe alguma diferença disparando ele no evento AffterInsert do CDS? acredito que não, só por curiosidade... :wink:
Marcos, já tentei o bookmark, não funciona, quanto ao ApplyUpdates eu que não entendi, qual seria o seu procedimento??
Eu sempre fiz assim:
-ClienteDataset.MODO(Insert,Edit etc)
-faço oq tem q ser feito
-ApplyUpdates;
-Refresh;
Desse modo , em ambiente de rede não é recomendado. Vc a cada Insert/Edit Trafega Dados na Rede.
O certo é fazer Tudo o que tem que ser feito <Varias Inserções, Varrios Edits> e no fim dar o Applyupdates. Assim os Dados são empacotados e enviados no mesmo Pacote
estou recebendo erros de campos não encontrados ao fazer este SELECT
Vc deve estar Usando o memso SqlQuery ou ClientDataSet para Fazer o Select , e ´eles´ Devem estar com os Fileds Definidos. Ou Talves oS Fileds
estão como Requeridos Logo na Montagem do Sql irá Reclamar
Geralmente neste tipo de problema uma Boa Prática de Programação
é o Uso de uma Função Genérica: Tipo esta
{O parâmetro TableName indica o nome da tabela da qual deseja-se
pegar o valor do generator que está associado a ela, sendo
que os generators criados no banco devem seguir o padrão
GEN_NomeTable_ID. Caso os generators do seu banco
não estejam neste padrão, altere o código desta função
para o formato do nome do seu generator. O nome do generator
poderia ser passado via parâmetro, ao invés de o nome
da tabela, porém, fica mais fácil simplesmente passar
o nome da tabela e a função montrar o nome do generator
a partir daí. Assim, o desenvolvedor não precisa
ficar pensando em como é o formato do nome
dos generators.
O parâmetro Incremento é um parâmetro Default. Se ele
for omitido na chamada da função, seu valor será 1.
Este valor indica que, antes de retornar o valor do generator,
este é incrementado com o valor do parâmetro Incremento, e é retornado
o valor do generator depois de incrementado. Se Incremento for passado
como zero, a função apenas devolve o valor atual do generator, sem
incremetá-lo.}function TSeuDataModulo.PrimaryKeyValue(TableName: ShortString;
Incremento: Byte): Integer;
var
dts: TSQLDataSet;
begin
//Cria um objeto local da classe TSQLDataSet
dts:= TSQLDataSet.Create(nil);
try
//Associa o dts à conexão SQLConnection1
dts.SQLConnection := SQLConnection1;
{gera um select para pegar o valor do generator
associado à tabela informado em TableName.
A tabela rdb$database é uma tabela de sistema, ou seja,
uma tabela interna do Firebird. Ela está sendo utilizada aqui
para executar selects que não trazem dados de nenhuma
tabela criada pelo desenvolvedor, e sim para executar
a função gen_id do Firebird. Como no Firebird, e em muitos outros bancos,
todo select deve possuir um "from NOME_TABELA"
(diferente do Microsoft SQL Server), então é usada
esta tabela interna do Firebird que sempre retorna apenas um registro
e permite a execuçã de função como gen_id, current_date, current_time, etc.}
dts.CommandText :=
´select gen_id(GEN_´ +
TableName + ´_ID, ´+IntToStr(Incremento)+´) from rdb$database´;
dts.Open;
//Pega o valor do generator
result:= dts.Fields[0].AsInteger;
dts.Close;
finally
dts.Free;
end;
end;Agora no Evento AfterInsert dos seu Cds voce coloque o Codigo
DataSet[´Seu_ID´]:=SeuDataModulo.PrimaryKeyValue(´NomeDaSuaTabela´)
GOSTEI 0
Marco Salles
19/09/2008
Marcos eu sempre disparo o gerador no evento BeforedUpDateRecord do DataSetProvider, existe alguma diferença disparando ele no evento AffterInsert do CDS?
O Seu Modelo eu não conheço e não o Utilizo. Vc poderia passar mais detalhes para Fazermos Um comparativo pequeno. Por exemplo tente entender a Minha dúvida abaixo:
Em relacionamentos como voce recupera esta Chave . Pois pelo modelo [b:46ca4fd734][u:46ca4fd734]proposto por voce[/u:46ca4fd734][/b:46ca4fd734] a cada Inserção , será necessário dar Um ApplyUpdates apos cada Insert. Pois o Evento [u:46ca4fd734]BeforedUpDateRecord[/u:46ca4fd734] so é disparado qnd os Dados são enviados
então vejo um inconveniente-> Dar applyupdates em cada Insert caso necessite da Chave para Relaconamentos
GOSTEI 0
Paullsoftware
19/09/2008
[quote:a147362d04=´Marco Salles´]
O Seu Modelo eu não conheço e não o Utilizo. Vc poderia passar mais detalhes para Fazermos Um comparativo pequeno. Por exemplo tente entender a Minha dúvida abaixo:
Em relacionamentos como voce recupera esta Chave . Pois pelo modelo [b:a147362d04][u:a147362d04]proposto por voce[/u:a147362d04][/b:a147362d04] a cada Inserção , será necessário dar Um ApplyUpdates apos cada Insert. Pois o Evento [u:a147362d04]BeforedUpDateRecord[/u:a147362d04] so é disparado qnd os Dados são enviados
então vejo um inconveniente-> Dar applyupdates em cada Insert caso necessite da Chave para Relaconamentos[/quote:a147362d04][u:a147362d04][b:a147362d04]não exatamente[/b:a147362d04][/u:a147362d04], mais vou preparar um exemplo e postar aqui :wink:
Marcos eu sempre disparo o gerador no evento BeforedUpDateRecord do DataSetProvider, existe alguma diferença disparando ele no evento AffterInsert do CDS?
O Seu Modelo eu não conheço e não o Utilizo. Vc poderia passar mais detalhes para Fazermos Um comparativo pequeno. Por exemplo tente entender a Minha dúvida abaixo:
Em relacionamentos como voce recupera esta Chave . Pois pelo modelo [b:a147362d04][u:a147362d04]proposto por voce[/u:a147362d04][/b:a147362d04] a cada Inserção , será necessário dar Um ApplyUpdates apos cada Insert. Pois o Evento [u:a147362d04]BeforedUpDateRecord[/u:a147362d04] so é disparado qnd os Dados são enviados
então vejo um inconveniente-> Dar applyupdates em cada Insert caso necessite da Chave para Relaconamentos[/quote:a147362d04][u:a147362d04][b:a147362d04]não exatamente[/b:a147362d04][/u:a147362d04], mais vou preparar um exemplo e postar aqui :wink:
GOSTEI 0
Marco Salles
19/09/2008
então , prepare um Modelo simples usando um relacionamento com DbExpress ... Gostaria de fazer um comparativo como vc recupera este Id, neste evento.
No Aguardo
No Aguardo
GOSTEI 0
Paullsoftware
19/09/2008
Tá bem simples, mas dá pra você ver como eu faço na maioria dos meus relacionamentos...
[url=http://www.safpe.com.br/externo/Master-Detail.rar]LINK DO EXEMPLO[/url]
da uma olhada ai :wink:
[url=http://www.safpe.com.br/externo/Master-Detail.rar]LINK DO EXEMPLO[/url]
da uma olhada ai :wink:
GOSTEI 0
Marco Salles
19/09/2008
Beleza Paulo.. Fiz o Downlooad e fui verificar como voce estava dando o
Applyupdates. É como eu suspeitava . Vc esta dando o ApplyUpadates no
evento cdsMasterAfterPost .
O que eu penso , que num ambiente DeskTop não terá problemas. Mas num Ambiente de Rede no meu entendimento , não é a Prática correta.
O Ideal é fazer vária inserçoes , ediçoes e no Fim enviar tudo para ser salvo Nun so Pacote.
Isto é o que eu acho e penso , não deu para continuar a análise pq no exemplo enviado por voce não dá para Atualizar os Dados do Detalhes.
a não ser que apos inserir Dados no Detalhe o usuário click no botão correspondente ApplyUpdates do Mestre -->> Algo pouco sugestivo para um leigo ou quem for usar o Programa pela primeira Vez
conclusão:
Eu ainda não consegui ver o ganho em dar um ApplyUpdates em cada Inserção do Mestre. Salvo no Seu exemplo que se Obtem o ID no Evento
dspMasterBeforeUpdateRecord o que pode ser feito na minha Opinião no
evento dos Cds (efetuando um Select no Banco) sem ter que sobrecarregar o Banco e ganho em performance ( Pelo menos é o que tenho Lido )
espero ter sido claro. Pode ser que algo não tenha ficado claro para mim
Applyupdates. É como eu suspeitava . Vc esta dando o ApplyUpadates no
evento cdsMasterAfterPost .
procedure TDMCadastro.cdsMasterAfterPost(DataSet: TDataSet); begin TClientDataSet(DataSet).ApplyUpdates(-1); end;
O que eu penso , que num ambiente DeskTop não terá problemas. Mas num Ambiente de Rede no meu entendimento , não é a Prática correta.
O Ideal é fazer vária inserçoes , ediçoes e no Fim enviar tudo para ser salvo Nun so Pacote.
Isto é o que eu acho e penso , não deu para continuar a análise pq no exemplo enviado por voce não dá para Atualizar os Dados do Detalhes.
a não ser que apos inserir Dados no Detalhe o usuário click no botão correspondente ApplyUpdates do Mestre -->> Algo pouco sugestivo para um leigo ou quem for usar o Programa pela primeira Vez
conclusão:
Eu ainda não consegui ver o ganho em dar um ApplyUpdates em cada Inserção do Mestre. Salvo no Seu exemplo que se Obtem o ID no Evento
dspMasterBeforeUpdateRecord o que pode ser feito na minha Opinião no
evento dos Cds (efetuando um Select no Banco) sem ter que sobrecarregar o Banco e ganho em performance ( Pelo menos é o que tenho Lido )
espero ter sido claro. Pode ser que algo não tenha ficado claro para mim
GOSTEI 0
Paullsoftware
19/09/2008
[quote:581246aa76=´Marco Salles´]Beleza Paulo.. Fiz o Downlooad e fui verificar como voce estava dando o
Applyupdates. É como eu suspeitava . Vc esta dando o ApplyUpadates no
evento cdsMasterAfterPost .
O que eu penso , que num ambiente DeskTop não terá problemas. Mas num Ambiente de Rede no meu entendimento , não é a Prática correta.
O Ideal é fazer vária inserçoes , ediçoes e no Fim enviar tudo para ser salvo Nun so Pacote.
[/quote:581246aa76] entendo Marcos, porém, nas empresas que prestei algum serviço de desenvolvimento eles não querem perder o ID no caso de um cancelanto da inserção, pois, disparando o ID no Insert do CDS se houver um cancelamento ele não vai voltar para o ID gerado anteriormente, mas sim para um próximo...
Com relação ao envio de vários registros ao mesmo tempo, isso realmente só seria possivel retornando o ID antes da maneira que você mecionou. Eu até fiz essa proposta pro chefe mas ele não quis, pois, quer ter um controle sequencial dos dados, e até agora o sistema funciona perfeitamente usando Multcamadas WebService SOAP + DbExpress.
Não entendi...
Applyupdates. É como eu suspeitava . Vc esta dando o ApplyUpadates no
evento cdsMasterAfterPost .
procedure TDMCadastro.cdsMasterAfterPost(DataSet: TDataSet); begin TClientDataSet(DataSet).ApplyUpdates(-1); end;
O que eu penso , que num ambiente DeskTop não terá problemas. Mas num Ambiente de Rede no meu entendimento , não é a Prática correta.
O Ideal é fazer vária inserçoes , ediçoes e no Fim enviar tudo para ser salvo Nun so Pacote.
[/quote:581246aa76] entendo Marcos, porém, nas empresas que prestei algum serviço de desenvolvimento eles não querem perder o ID no caso de um cancelanto da inserção, pois, disparando o ID no Insert do CDS se houver um cancelamento ele não vai voltar para o ID gerado anteriormente, mas sim para um próximo...
Com relação ao envio de vários registros ao mesmo tempo, isso realmente só seria possivel retornando o ID antes da maneira que você mecionou. Eu até fiz essa proposta pro chefe mas ele não quis, pois, quer ter um controle sequencial dos dados, e até agora o sistema funciona perfeitamente usando Multcamadas WebService SOAP + DbExpress.
Isto é o que eu acho e penso , não deu para continuar a análise pq no exemplo enviado por voce não dá para Atualizar os Dados do Detalhes.
a não ser que apos inserir Dados no Detalhe o usuário click no botão correspondente ApplyUpdates do Mestre -->> Algo pouco sugestivo para um leigo ou quem for usar o Programa pela primeira Vez
Não entendi...
GOSTEI 0