Chave primária com ClientDataSet(CDS)

22/11/2005

0

Olá pessoal,
Estava com um problema num projeto da facul, e já estava pra postar aqui, mas agora a coisa ficou pior pq surgiu o mesmo problema no trampo. Preciso de uma rotina segura para a manipulação das chaves primárias no meu banco. Já dei uma pesquisada e o melhor q eu achei foi fazer uma função recursiva q dá um applyupdates com um novo valor de chave qdo dá erro. Porém, não acho q seria o ideal, pois no help eu verifiquei q existe o evento on UpdateError para manipular esse tipo de problema, e me pareceu a melhor solução. Só q eu não entendi como se utiliza esse evento. Se alguem puder me dar uma :idea: eu ficarei muito grato.
Ah... O meu trabalho da facul é um desafio um pouco maior. É um mestre-detalhe. Aí a minha dúvida é a seguinte: Eu posso manipular só a chave do CDS mestre, ou eu preciso fazer isso com o CDS detalhe também.

Muitoi obrigado pela ajuda.
Leomar de Rossi Ferreira


Lero

Lero

Responder

Posts

22/11/2005

Emerson Nascimento

uma pergunta: sua chave-primária é um campo auto-incremental?


Responder

22/11/2005

Lero

Não, é um integer comum mesmo. Eu não gosto de trabalhar com chave auto-incremental, pq não me permite ter controle pleno dos dados.

Leomar de Rossi Ferreira.


Responder

22/11/2005

Lero

Tentei fazer com o seguinte código no UpdateError do datasetprovider:

  begin
    cdsAgendaagenda_id.NewValue := StrToInt(VarToStr(cdsAgendaagenda_id.Value)) + 1;
    Response := rrApply;
  end;


O problema é q qdo ele vai setar o NewValue, ele dá um erro de ´Falha Catastrófica´. Como faço para setar a NewValue corretamente? Acho q se conseguir setar o problema tá resolvido. Qualquer ajuda serve, por favor.

Leomar de Rossi Ferreira


Responder

22/11/2005

Emerson Nascimento

sugiro que você faça essa avaliacão no evento OnUpdateRecord do provider. verifique o tipo de atualização (ukInsert) e preencha ali o seu campo-chave.


Responder

22/11/2005

Lero

Mas e se tiverem processos concorrentes? Utilizando o UpdateRecord não existe a possibilidade de dois ou mais usuários pegarem o mesmo valor ao mesmo tempo? A minha idéia era ´insistir´ com o BD até q o DataSetProvider coloque um valor q não viole a chave?

Ahhh... Eu tô dando o ApplyUpdates dentro de uma transação, claro. A transação impediria a colocação de duas chaves com o mesmo valor ao mesmo tempo? Quero dizer, se eu indicar o valor no UpdateRecord e o DSP aplicar o insert sem erro, outro cliente q busque a chave após o insert, mas durante a transação antes do commit vai ter retornado qual valor? De qualquer forma ainda poderia haver erro, pois o outro cliente pode pegar o valor antes do insert, mas é uma dúvida q eu tenho há algum tempo.

Leomar de Rossi Ferreira


Responder

22/11/2005

Emerson Nascimento

um valor chave não deve ser informado no momento do insert. a menos que esse valor possa ser desprezado.
por exemplo:
usuario A inseriu. codigo 1;
usuario B inseriu. codigo 2;
usuario B gravou; codigo 2;
usuario A cancelou;
dessa forma pode acontecer de ficarem ´buracos´ entre os códigos.


se a atribuição for feita somente no momento da gravação (o ukInsert do OnUpdateRecord só acontece no momento do ApplyUpdates, porque o provider só reconhece a inserção no momento em que ela for descarregada para o HD)
usuario A inseriu.
usuario B inseriu.
usuario C inseriu.
usuario B gravou; codigo 1;
usuario A cancelou;
usuario C gravou; codigo 2;


Responder

23/11/2005

Lero

Emerson,
Acho q não entendi direito. No exemplo q vc deu se o usuário A cancela a gravação e o B grava, a chave do registro do B seria 1, mas se o A gravasse, a chave seria 2 para o B. O q eu não entendi é como eu faço pro cliente receber um valor de chave único sendo q ainda não foi gravado no banco. Eu não sei como se faz isso, se vc puder me dar uma orientação, eu agradeço.
Ah... Eu não achei o evento [b:8404ba2482]onUpdateRecord[/b:8404ba2482], no [b:8404ba2482]DataSetProvider[/b:8404ba2482] só tem [b:8404ba2482]BeforeUptdateRecord e AfterUpdateRecord[/b:8404ba2482]. No CDS tb não tem, nem no ADODataSet q está ligado ao provider. Em qual componente ele fica? (o meu Delphi é o 7)

De qualquer forma, acho q o ideal pra mim seria utilizar o [b:8404ba2482]OnUpdateError[/b:8404ba2482], só q qdo eu tento alterar o [b:8404ba2482]TField.NewValue[/b:8404ba2482] ele dá erro de [b:8404ba2482]´Falha Catastrófica´[/b:8404ba2482] :shock: . Tô achando q esse problema é por causa da mistura explosiva ADO + DSP + CDS. Alguém já teve esse problema?


Responder

23/11/2005

Emerson Nascimento

me desculpe. o evento é BeforeUpdateRecord do DatasetProvider.

agora, para poder te ajudar de forma satisfatória, como você adquire o valor da chave? pega o último valor e soma um, ou tem uma tabela que controla a numeração?


Responder

23/11/2005

Lero

Pego o maior valor e somo 1. Mas vou fazer uma rotina pra pegar o menor valor disponível. Acho q vou criar uma function no próprio banco de dados pra isso.


Responder

23/11/2005

Emerson Nascimento

tenha no seu Datamodule uma query para uso generico. eu sempre crio uma com o nome de dataset_geral. eis um exemplo de uso com sql para buscar o último codigo.

procedure TForm1.DataSetProvider1BeforeUpdateRecord(Sender: TObject;
  SourceDS: TDataSet; DeltaDS: TCustomClientDataSet;
  UpdateKind: TUpdateKind; var Applied: Boolean);
var
  proximocodigo: integer;
begin
  case UpdateKind of
    ukInsert:
      if SourceDS = SeuADODataset then
      begin
        // pega o próximo codigo
        with ADODataset_geral do
        begin
          close;
          commandtext := ´select max(codigo) from tabela [where...]´;
          open;
          if fields[0].isnull
          then proximocodigo := 1
          else proximocodigo := fields[0].asinteger + 1;
          close;
        end;
        DeltaDS.FieldByName(´codigo´).newvalue := proximocodigo;
      end;
  end;
end;


adicione a opção poPropagateChanges na propriedade Options do Provider para que o novo código seja exibido no seu dataware após a gravação.


Responder

24/11/2005

Lero

Blz. Valew mesmo por toda a ajuda, Emerson. Fiz do jeito q vc falou, no BeforeUpdateRecord e tá funcionando legal, só falta fazer a function no banco pra evitar os intervalos entre os valores. Aproveitei pra implementar essa técnica no meu trabalho da facul q tem master-detail e ficou perfeito.
Mais uma vez, muito obrigado pela sua colaboração.

Leomar de Rossi Ferreira


Responder

24/11/2005

Emerson Nascimento

amigo, da forma que eu te passei não ficam intervalos entre os valores:
- os valores serão atribuídos somente na execução do applyupdates.
- só haverá intervalos se por acaso vc estiver no código 5 e algum usuário excluir o registro 3. obviamente o próximo será o 6 e o haverá o ´buraco´ do 2 para o 4.
sinceramente eu nunca soube o porquê de controlar isso. geralmente o campo-chave é invisível para o usuário. é utilizado internamente, principalmente para relacionamento entre tabelas.

em tempo: para sua maior comodidade eu sugiro ainda que você trabalhe com tabelas aninhadas. as famosas nested tables.


Responder

Que tal ter acesso a um e-book gratuito que vai te ajudar muito nesse momento decisivo?

Ver ebook

Recomendado pra quem ainda não iniciou o estudos.

Eu quero
Ver ebook

Recomendado para quem está passando por dificuldades nessa etapa inicial

Eu quero

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar