Em algumas situações de um projeto (Delphi no ambiente Win32), trabalhando com o NestedDataSet (Estrutura Mestre Detalhe DbExpress ClientDataSet), deparamos com uma situação que parece simples e que deveria ser simples, mas esta longe disso. Fazer um filtro na Tabela Mestre com alguma condição da Tabela Detalhe. Lembrando que na Tabela Mestre não tem os campo da Tabela Detalhe.

A Saída simples, seria usar JOIN ou mesmo un IN entre essas tabelas. Mas ai vc para e pergunta: "Um SQL vai consumir recurso de Rede, e esses dados estão aqui, bem pertinho de mim, por outro lado , o Servidor pode esta em outro lugar bem distante neste mundão. Ou mesmo vc esta trabalhando desconectadamente num LapTop e ortanto sem conexão com o Servidor. Portanto não seria pedir nada de mais, que esse filtro pudesse ser feito localmente. Mas como fazer? O que o Delphi tem a nos fornecer de maneira RAD para completarmos nais esta tarefa?"

Confesso que nas andanças por este forums, sites,relacionamentos afins, não encontrei nada nativo do Delphi. Nenhum Recurso atê a versão 2010. Sabemos que um Filtro no clientDataSet que pudesse resolver o problema tem mais ou menos a estrutura abaixo

ClientDataSet.Filtered:=false;
ClientDataSet.Filter:=’CAMPO OperadorLogico Condicao’;
ClientDataSet1.Filtered:=True;

E Esta estrutura nos ajuda em muitos casos , concatenando condiçoes, usando o operador LIKE enfim numa série de condições que nos deixam quase cem por cento de satisfação. Afinal trata do ClientDataset um dos melhores componentes ja criados se não o MELHOR!

Mas o nosso “PROBLEMA”, é que esta Condicao esta na Tabela DETALHE e pode nen existir na Tabela MESTRE. Além disso vale ressaltar que um filtro na TAbela DETALHE, não resolve o nosso Problema, porque funciona na Tabela DETALHE, mas os registros na Tabela Mestre Não são filtrados. Estamos diante de uma situação e esta delongas, são para vcs entenderem o tamanho do problema.

Mas pera ai, num relacionamento Utilizando o NestedDataSet, tem um campo que se refere a Tabela Detalhes. Nele temos tudo que precisamos. Todos os Campos, todos os Dados da Tabela DETALHE. Que dizer que existe um campo na Tabela MESTRE do Tipo TDataSetField (Assim como temos os Tipo TIntegerField, TStringField etc. Temos tb o TDataSetField).

Então vamos usar este campo na Estrutura anterior. É uma Idéia, seria uma Idéia, funcionaria se subessemos, ou nos fosse fornecido algum operador Lógico para comparmos esses Tipos. Comparar com que, e ainda, como Comparar? São perguntas que, para eu falta resposta, e se alguem tiver que a coloque no Blog. Facilitaria muitas as coisas.

Como bom Brasileiro eu não desisto nunca e tive que partir para outros artificios e resolvi o probrema utilizando a propriedade DATA do ClientDataSet juntamente com o evento FilterRecord do ClientDataSet MESTRE.

No campo Private do Formulário declare um Objeto do Tipo TClientDataSet, que chamaremos aqui de cdsAUX. Este Objeto sera responsável por receber em memória os Dados da Tabela DETALHE (TELEFONES) representados aqui pelo componente cdsDETALHE.

A outra Tabela envolvida e a Tabela MESTRE (PESSOA) representada respctivamente pelo cdsMESTRE, por fim destacamos que a as duas tabela (PESSOA e TELEFONE ) se relacionam atraves do campo ID_PESSOA, e o nosso objetivo sera Filtrar os dados da tabela Mestre, com a condicação que os dados da Tabela Telefone tenha o Valor de um determinado RAMAL (campo da tabela TELEFONES, portanto um campo da Tabela DETALHE).

 cdsDETALHE.Filtered:=false;
 cdsDETALHE.Filter:= ‘RAMAL = ‘+quottostr(edtPesquisa.Text);
 cdsDETALHE.Filtered:=True;

So estaremos filtrando a tabela DETALHE e a Tabela Mestre Continuara exibindo Registro que não atende a especificação de um determinado Ramal. Isto ja foi comentado exaustivamente acima , mas é sempre relembrarmos o nosso problema e o nosso objetivo.

Então depois da declaração do objeto do tipo TClientDataSet, que chamamos de CdsAux no private do Form, vamos as condificações necessárias: que são os passos seguintes:

Primeiro instanciamos o Objeto


 procedure TFrmExemploPesquisaMestreDetalhe.FormShow(Sender: TObject);
begin
CdsAux:=TClientDataSet.Create(nil);
end;

Segundo definimos o evento ou método pesquisar (aqui fizemos dentro do onclik de um botão, mas nada que não possa evoluir para um método, passando os devidos parãmetros). Segue sua codificação:

procedure TFrmExemploPesquisaMestreDetalhe.btnPesquisaClick(Sender: TObject);
begin
 cdsMESTRE.Filtered:=False;
 cdsAux.Data:=cdsDETALHE.Data;
 cdsMESTRE.Filtered:=True;
 cdsDETALHE.Filtered:=false;
 cdsDETALHE.Filter:= ‘(upper(RAMAL) like upper(‘+QuotedStr(Trim(‘%’+edtPesquisa.Text+’%'))+’))’;
 cdsDETALHE.Filtered:=True;
end;

Antes de presseguir um adendo. Este filtro do jeito que ele esta Aplicado é InCaseSentive e alem disso utiliza a Busca em qualquer lugar do Registro. Assim se for Pesquisado por “A” ou “a” , acharemos Maria, Amara, joana enfim, todos os registros que tenham ou contenha o que for passado no EdtPesquisa.text.

Esta característica pode ser Alterada a gosto. Fizemos assim por acharmos mais expansivel. É melhor tirar coisas a mais do que colocar coisa a mais, ou seja é mais fácil tirar do que tem do que colocar no que não tem (“Trocadilho” rsss..).

Por fim aonde as coisa de fato ocorrem. No evento MESTREFilterRecord do Cds Mestre escreva:


procedure TFrmExemploPesquisaMestreDetalhe.cdsMESTREFilterRecord(DataSet: TDataSet;
  var Accept: Boolean);
begin
cdsAux.Filtered:=false;
CdsAux.Filter:=’(ID_PESSOA = ‘+DataSet.FieldByName(‘ID_PESSOA’).AsString+’)and’+
              ‘(upper(RAMAL) like upper(‘+QuotedStr(Trim(‘%’+edtPesquisa.Text+’%'))+’))’;
cdsAux.Filtered:=True;
Accept:=cdsAux.RecordCount > 0;
end;”

Lembrando sempre que o campo Id_Pessoa é o Relacionamento e O campo “Ramal” e o campo da Tabela Detalhe que queremos condicionar na Tabela MESTRE. No exemplo que vc fizer tem que trocar essas referências para o seu caso particular.

O último não tão menos importante é a destruiçao do objeto instanciado por nós e de nossa responsabilidade.


procedure TFrmExemploPesquisaMestreDetalhe.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
CdsAux.Free;
end;

Os teste realizados, foram feitos com um range de dados não muito grande. Existe ainda a possibilidade de melhorar a performance utilizando Indices e outros métodos de pesquisa indicado para um Range maior de Dados. Todavia não vem ao encontro do objetivo de resolver toda e qualquer situação, mas sim mostrar que quando não se tem cão, se caça com gato.

Resta ainda agradecer a paciência pela leitura e reafirmar que esta, talves não seja a melhor solução para o caso e ficaremos muitos honrados se alguem com sua experiência, indicar não so para eu, mas para quem de interresse for, um método mais eficaz e principalmente nativo da VCL. Enquanto este método não vem, vamos caçar com o gato.

Saiu na DevMedia!

  • Guia de UML:
    Você planeja suas aplicações antes de começar a programar? Ou é daqueles que pensa enquanto escreve? Cuidado, você corre o risco de chegar no meio do projeto sem saber para onde ir. Para evitar isso descubra neste Guia a UML.
  • Curso de HTML5:
    Formulários são uma parte fundamental da web, pois são a forma mais básica de interação com o usuário. Isso porque permitir o envio de dados para um servidor. Nesse curso criaremos um formulário de cadastro da pizzaria Hello Pizza, permitindo assim aprender sobre os elementos que o compõem e seus sistemas de validação.
  • Curso de C#:
    Este curso é voltado aos iniciantes na programação, principalmente na linguagem C#. Criaremos uma aplicação voltada a calcular o gasto de tinta necessário para pintar um cômodo utilizando conceitos básicos do C#, a principal linguagem de programação da plataforma .NET.

Saiba mais sobre Mestre Detalhe ;)

  • É tudo ou nada: gravando múltiplos registros de uma vez:
    Já pensou pagar por 10 itens, mas no final a aplicação só registrar a compra de 5 deles? Tem horas que não dá pra falhar. Fique por dentro dos problemas que podem ocorrer ao gravar múltiplos registros de uma só vez. Assista!
  • Mestre Detalhe em detalhes:
    Você provavelmente já se deparou com um formulário do tipo mestre detalhe enquanto fazia compras, selecionava suas matérias do semestre, etc. Mas você conhece todas as pequenas armadilhas que a programação dessa rotina esconde? Descubra neste DevCast
  • Construindo uma aplicação mestre detalhe em PHP:
    Ao longo deste curso veremos como implementar um formulário "mestre detalhe", nos concentrando nos aspectos principais desse relacionamento e como ele é representado no código, na interface do sistema e no banco de dados.