CloneCursor como definir os parâmetros Reset KeepSettings ClientDataSet Delphi

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 mau 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 ClientDataSet 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 só 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.ApplyUpdates 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.ApplyUpdates , 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 essa propriedades está o ProviderName . Neste caso o ProviderName estará em Branco e vc não conseguira aplicar (comitar) no Banco de Dados (ApplyUpdates)

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 metodo inerente a sua necessidade , de modo que quando vc fizer um clientDataSet.ApplyUpdates este evento seja disparado . Irá ocorrer novamente um problema , porque o ProviderName que foi definido originalmente pelo clone será apagado (sobre escrito) pelo ProviderName que foi definido pelo clientDataSetFonte e o tão esperado evento BeforeUpdateRecord 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.ApplyUpdates 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

Com isto percebem que para clonar uma fonte de dados teremos então tres possiveis situaçõess

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

Vamos á prática … Utilizando DbExpress (ou outro modo de acesso) crie uma conexão com a sua base de dados preferida . Adicione dois DataSetProvider e altere seu Nomes respectivamente para Provider_Do_Cds_Fonte , Provider_Do_Clone_Cursor . Adicione ao projeto um Button e no Evento Onclick codifique

procedure TForm7.Button1Click(Sender: TObject);
var
cds_Fonte,Cds_Clone:TclientDataSet;
begin
cds_Fonte:=TclientDataSet.Create(self);
cds_Fonte.providerName:='Provider_Do_Cds_Fonte';
cds_Fonte.Open;

Cds_Clone:=TclientDataSet.Create(nil);
cds_Clone.ProviderName:='Provider_Do_Clone_Cursor';

Cds_Clone.CloneCursor(cds_Fonte,true,true);
//Cds_Clone.CloneCursor(cds_Fonte,true,false); INDIFERENTE > Tanto Faz
showmessage(Cds_Clone.ProviderName); //vazio .. Foi Resetado
Cds_Clone.Close;
cds_Clone.ProviderName:='Provider_Do_Clone_Cursor';

//As´proproedades serão do Cds Fonte de dados
Cds_Clone.CloneCursor(cds_Fonte,false,false);
showmessage(Cds_Clone.ProviderName); //cds_Fonte de Dados
Cds_Clone.Close;
cds_Clone.ProviderName:='Provider_Do_Clone_Cursor';

//As proriedades serão do Clone_Cursor como pode se visto abaixo
Cds_Clone.CloneCursor(cds_Fonte,false,True);
showmessage(Cds_Clone.ProviderName); //cds_Clone_Cursor
cds_Fonte.Free;
Cds_Clone.Free;
end;

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 .

Sobre marcosalles

Delphiano de Coração Desenvolvo FreeLancer e presto Consultoria Orientação Online DataSnap DbX ClientDataSet , POO , Padrões de Projeto e dúvidas de Delphi em Geral
Esse post foi publicado em Dicas e marcado , , , . Guardar link permanente.

Deixe um comentário