O foco principal deste artigo  é como definir os parâmetros Reset KeepSettings do método cloneCursor .  O que esses parâmetros trazem de diferente ao se clonar um clientDataSet ? Ou mesmo ,  o que pode ocasionar uma escolha mal feita ou uma desatenção na hora de definirmos esses parâmetros ? Antes disto vamos a uma breve introdução do método em si

Quando você clona os dados de um ClientDataSet , você cria  não apenas um ponteiro adicional para um armazenamento de memória  compartilhada, mas também uma visão independente dos dados. Quando falo de ponteiros , me refiro a necessidade de deslocarmos todos os dados sem perdermos a localização do ponteiro inicial ou vice versa .Quando  falo de visão independente de dados , falo no sentido de podermos aplicar filtros , índices , ranges nesta nova visão de dados sem afetar a visão dos dados iniciais ou vice-versa .   Apesar de termos uma Visão diferente não se pode  modificar os dados de um sem afetar o conjunto de dados do Outro , pois ele é compartilhado na memória. Toda alteração , inserção , eliminação em um , automaticamente será refletidas para o outro e vice versa .

Vamos a definição do método

procedure CloneCursor(Source :TCustomClientDataSet; Reset: Boolean; KeepSettings: Boolean = False);

Nos exemplos que se seguem iremos sempre referenciar o Objeto Ativo ClientDataSet o qual iremos clonar de CdsFonteDeDados e o Objeto que receberá essa fonte de dados de CloneCds

 
Para usa-la fazemos assim:
    cloneCds:TClientDataSet;
  begin
    cloneCds.CloneCursor(CdsFonteDeDados,Reset ??,KeepSettings ???)
  end;

O primeiro parâmetro é a fonte dos dados que vc quer clonar ou obter . Este argumento tem que ser um ClinteDataSet ativo e que aponte para o armazenamento de memória que vc quer acessar .  Muito intuitivo este argumento e dispensa comentários adicionais

O Segundo parâmetro atua juntamente com o terceiro . Porém se pudéssemos aqui utilizar uma analogia com a genética , diríamos que o segundo parâmetro é o gene dominante . de modo que o terceiro parâmetro  vai influenciar se o segundo parâmetro for recessivo . Então se o Reset:=True (Dominante) , indepedentemente do valor que se atribui para KeepSettings (False ou True) , a característica do Clone já esta traçada e não há como fazer mais nada . Então para efeito de estudo passamos a ter um conjunto de Três situações possíveis que devemos analisar e comentar que são :

  • Reset:= False ; KeepSettings:=False  ****
  • Reset:= False ; KeepSettings:=True
  • Reset:= true ; KeepSettings:=False ou KeepSettings:=True **** Tanto faz

vamos começar com) Reset igual a true .. KeepSettings (False ou True) tanto faz

O Parâmetro Reset como o próprio nome já diz , vai resetar toda e qualquer propriedade que possa já existir (no sentido de que já foi definida) no Clone . Que propriedades seriam estas ?  Por exemplo os valores de IndexName (ou IndexFieldNames), filter, filtered, MasterSource, MasterFields, OnFilterRecord e ProviderName

Leia com muita atenção , pois isto é importante e vou prova-lo . Imagine que vc tenha um clientDataSet com a propriedade ProviderName definida com o nome de algum TDataSetProvider . Imagine ainda que vc definiu no evento BeforeUpdateRecord deste Provider um método inerente a sua necessidade , de modo que quando vc fizer um clientDataSet.ApplayUpdates este evento seja disparado . Ai vc usa um uma fonte de dados e o repassa a este clientDataSet definindo no método o Reset como True . Mas na hora do ClientDataSet.ApplayUpdates , as coisas não ocorrem do jeito que vc pensou e depois de quatro horas (projeto grande cheio de herança..) , vc descobre que o evento BeforeUpdateRecord não esta sendo executado ... Mas como ???? A resposta pode agora ser simples , mas nem tanto obvia para quem desconhece o parâmetro Reset . Ao utilizar o Reset = True , as propriedades definidas no clientDataSet serão resetadas , e entre essas propriedades está o ProviderName . Neste caso o ProviderName estará em Branco e vc não conseguira aplicar (comitar) no Banco de Dados (ApplayUpdates)

Segundo caso) Reset:= False ; KeepSettings:=False 

O Reset sendo False o método passa a olhar para a definição do terceiro parâmetro para definir o comportamente do clone . Como  o terceiro parâmetro nesta situação tb é Falso , o gene dominante será o Reset . O Reset=false implica que as propriedades que o clone usará são as que forem definidas (forem ou estão) pelo clientDataSetFonte . Que propriedades seriam essas ? Mais uma vez , os valores de IndexName (ou IndexFieldNames), filter, filtered, MasterSource, MasterFields, OnFilterRecord e ProviderName .

Agora pense novamente na situação levantada acima , onde vc tem clientDataSet com a propriedade ProviderName definida com o nome de algum TDataSetProvider . Imagine ainda que vc definiu no evento BeforeUpdateRecord deste Provider um método inerente a sua necessidade , de modo que quando vc fizer um clientDataSet.ApplayUpdates este evento seja disparado . Irá ocorrer novamente um problema , porque o ProviderName que foi definido originalmente pelo clone será apagado e sobre escrito pelo ProviderName que foi definido pelo clientDataSetFonte e o tão esperado evento BeforeUpdateRecord  que vc escreveu não será disparado . Por conta da sobreposição o ProviderName do Clone aponta (na verdade não se trata de um ponteiro mas por hora pensemos assim) para o TDataSetProvider que foi definido no CdsFonteDeDados , e é o evento BeforeUpdateRecord deste Provider que será excecutado ..

 
Terceiro caso) Reset:= False ; KeepSettings:=True

O Reset sendo False o método passa a olhar para a definição do terceiro parâmetro para definir o comportamento do clone . Como  o terceiro parâmetro nesta situação é True, o gene dominante será o KeepSettings . O  KeepSettings qnd dominante implica que as propriedades que do clone não serão sobrescritas pelo clientDataSetFonte . Que propriedades seriam essas ? Pela terceira vez, os valores de IndexName (ou IndexFieldNames), filter, filtered, MasterSource, MasterFields, OnFilterRecord e ProviderName .

Pela terceira vez pensaremos na situação levantada acima , onde vc tem clientDataSet com a propriedade ProviderName definida com o nome de algum TDataSetProvider . Imagine ainda que vc definiu no evento BeforeUpdateRecord deste Provider um método inerente a sua necessidade , de modo que quando vc fizer um clientDataSet.ApplayUpdates este evento seja disparado . Como agora o ProviderName do Clone e as demais propriedades (digamos assim , são as originais as que foram previamente definidas) , o tão esperado evento BeforeUpdateRecord  será executado ... Ebaaaaaaaaaaaaaaaaaaaaaaaa . Ufa , consegui !!!!!

Com isto percebem que para clonar uma fonte de dados teremos então tres possíveis situações

  • CloneCds.CloneCursor(CdsFonteDeDados,false,false);//Propriedade do CdsSetFonteDeDados
  • CloneCds.CloneCursor(CdsFonteDeDados,false,True); // Propriedade do CloneCds
  • CloneCds.CloneCursor(CdsFonteDeDados,True,false ou True); //Propriedade do CloneCds RESETADAS

A forma que vc irá utilizar este importante método sera inerente á sua necessidade, a intenção aqui foi mostrar possiveis causas de erros e dores de cabeça ao se utilizar o método . Vale ressaltar que o último parâmetro é opcional ( caso não se define ele assumirá KeepSettings=False )

No mais ainda tem alguma particularidades que não foram abordadas , por questões de tempo , paciência e espaço . O que deve ficar claro que é muito bonito usar cloneCursor , mas devemos saber por onde passam as coisas . No mais , estou aberto a qualquer crítica e de prontidão para recebe-la , meu muito obrigado e atê a próxima .

Link Original