Clique para saber mais...
  Home     Download     Produtos / Cursos     Revista     Vídeo Aulas     Fórum     Contato   Clique aqui para logar | 07 de Setembro de 2026
  Login

Codinome
Senha
Salvar informações

 Esqueci minha senha
 Novo Cadastro

  Usuários
78 Usuários Online

  Revista ActiveDelphi
 Assine Já!
 Edições
 Sobre a Revista

  Conteúdo
 Apostilas
 Artigos
 Componentes
 Dicas
 News
 Programas / Exemplos
 Vídeo Aulas

  Serviços
 Active News
 Fórum
 Produtos / Cursos

  Outros
 Colunistas
 Contato
 Top 10

  Publicidade

  [Artigos]  Queries dinâmicas no servidor DataSnap
Publicado por rboaro : Quarta, Janeiro 23, 2013 - 07:44 GMT-3 (2547 leituras)
Comentários 7 Comentários   Enviar esta notícia a um amigo Enviar para um amigo   Versão para Impressão Versão para impressão
Marcos Salles Há muitos motivos para evitar o uso do commandText do clientDataSet , entre eles podemos destacar alguns pontos.

* A Descentralização de acesso a dados e de negócio abre um impácto negativo grande na manutenção desses aplicativos clientes.
* Dificuldade na reutilização de codigo
* Fragilidade a SQL Injection devido a Sql trafegando na Rede
* Dependência do banco e de seus recursos, o que causa pouca escalabilidade.

Abaixo transcrevo uma técnica de criar um SQL no servidor usando métodos presentes no CDS(Cliente) -> DSP(Servidor), este configurando seu proprio DataSet.

Quando eu digo que lugar de SQL é no servidor é porque vejo muitos programadores Delphi usando DataSnap como um simples middleware de conectividade com o banco de dados, não como uma verdadeira camada de “regras de negócio” que proporcione abstração de dados do lado cliente.
Uma dificuldade comum, que muitos consideram justificativa para usar a famigerada opção poAllowCommandText no TDataSetProvider, é fazer queries customizadas na aplicação cliente que não tenham um conjunto definido de parâmetros.
Como fazer uma pesquisa em um cadastro de clientes, por exemplo, por Cidade e/ou Nome e/ou Data de Cadastro? Só esses três parâmetros permitem 8 combinações de consulta (23). Uma solução seria escrever 8 queries diferentes no servidor e mais 8 dataset providers. Uma trabalheira danada. Já se fossem 5 campos de pesquisa para o usuário, seriam 32 combinações! Por aí que muita gente escolhe construir dinamicamente a query no cliente e usar a propriedade CommandText de TClientDataSet.
Uma alternativa é escrever uma query em que a cláusula WHERE contemple parâmetros nulos. Por exemplo:

WHERE
((:Cidade IS NOT NULL) AND (Cidade = :Bairro)) OR
((:Cadastro IS NOT NULL) AND (Cadastro >= :Cadastro))

O problema com essa técnica é que a performance da query fica muito comprometida. Não há como o otimizador do banco de dados fazer um plano de execução eficiente.
A minha solução preferida é simplesmente mandar os valores dos parâmetros para o TDataSetProvider montar a query dinamicamente. Falando assim parece simples, mas… na verdade é simples!
A chave é usar o evento BeforeGetRecords, presente tanto no TClientDataSet (no lado cliente), quanto no TDataSetProvider (no lado servidor). O evento tem um parâmetro OwnerData do tipo OleVariant (para todos efeitos, idêntico a um Variant) que pode ser atribuido no cliente e depois lido no servidor. Construí uma pequena aplicação de exemplo que lê a tabela Country do banco de dados Access de demonstração que fica em “…\Borland Shared\Data\dbdemos.mdb”. Veja abaixo uma imagem da aplicação filtrando os campos “Continent”, “Population” (valo mínimo) e “Name” (iniciais).

O que eu fiz no cliente foi apenas montar um array Variant com os parâmetros definidos pelo usuário e atribuí-lo a OwnerData. Não mexi com a propriedade Params do ClientDataSet simplesmente porque não existe nenhum parâmetro no dataset: o SQL será montado no servidor dinamicamente.

procedure TForm1.cdsCountryBeforeGetRecords(
Sender: TObject; var OwnerData: olevariant);
var
ContinentEqual: string;
PopulationMin: integer;
NameStart: string;
begin
ContinentEqual := Trim(Edit1.Text);
PopulationMin := StrToIntDef(Trim(Edit2.Text), 0);
NameStart := Trim(Edit3.Text);
OwnerData := VarArrayOf([ContinentEqual, PopulationMin, NameStart]);
end;

Com isso o cliente só precisa deixar o usuário entrar com os parâmetros que quiser na tela e dar Open no dataset (não esqueça de dar um Close antes de fazer uma nova pesquisa). O servidor se encarregará de montar o código SQL apropriado com os parâmetros que não forem vazios.
O mesmo evento BeforeGetRecords é usado no servidor de aplicação, mas agora usamos o do componente TDataSetProvider para alterar em código a propriedade SQL do objeto de query (no caso, um TADOQuery):

procedure TRemoteDataModule1.dspCountryBeforeGetRecords(
Sender: TObject; var OwnerData: olevariant);
var
ContinentEqual: string;
PopulationMin: integer;
NameStart: string;
SQLWhere: string;

procedure AddWhere(const S: string);
begin
if SQLWhere = ” then
SQLWhere := ‘WHERE’
else
SQLWhere := SQLWhere + ‘ AND’;
SQLWhere := SQLWhere + ‘ (‘ + S + ‘)’;
end;

begin
if VarIsArray(OwnerData) and (VarArrayHighBound(OwnerData, 1) = 2) then
begin
ContinentEqual := OwnerData[0];
PopulationMin := OwnerData[1];
NameStart := Ownerdata[2];

SQLWhere := ”;
if ContinentEqual = ” then
AddWhere(Format(‘Continent = ”%s”’, [ContinentEqual]));
if Populationmin &;gt; 0 then
AddWhere(Format(‘Population >= %d’, [PopulationMin]));
if NameStart = ” then
AddWhere(Format(‘Name LIKE ”%s%%”’, [NameStart]));

qryCountry.SQL.Clear;
qryCountry.SQL.Add(‘SELECT * FROM Country’);
qryCountry.SQL.Add(SQLWhere);
end;
end;

Veja abaixo o resultado de uma query mais específica, que define o continente “South America” e uma quantidade mínima de 100.000.000 habitantes. Com essa técnica a aplicação cliente fica totalmente independente da estrutura do banco de dados. Se mudar o banco de dados, ou mesmo a estrutura das tabelas, nada tem que ser alterado no cliente! O simples fato de isolar a camada de apresentação do acesso a dados já é uma vantagem na administração do projeto. Repitam comigo: CommandText nunca mais!

Link Original do Artigo:
http://marcosalles.wordpress.com/2011/01/23/queries-dinamicas-no-servidor-datasnap/


Comentários Comentários
   Ordem:  
Comentários pertencem aos seus respectivos autores. Não somos responsáveis pelo seus conteúdos.


por: marcosalles (salhamoda@uol.com.br) : Jan 25, 2013 - 06:43
(Informações sobre o membro | Enviar uma mensagem) http://marcosalles.wordpress.com/
Bom dia a todos .. Gostaria de um adendo sobre o Artigo . Como se faz sabido no link original , esta artigo não é de minha autoria , mas sim do Daniel Mata cujo o blog não existe mais . Porém gentilmente , o mesmo fez contato agradecendo a sua menção nas linhas onde cito a fonte original . []sds


por: deophanes (deophanes@click21.com.br) : Jan 28, 2013 - 01:28
(Informações sobre o membro | Enviar uma mensagem) http://
Olá Marcos, como posso fazer esse tipo de consulta usando o novo datasnap no delphi 2010?


por: marcosalles (salhamoda@uol.com.br) : Fev 03, 2013 - 12:12
(Informações sobre o membro | Enviar uma mensagem) http://marcosalles.wordpress.com/
Ok amigo ... Obrigado pelo feedback
  Edição 112

Revista ActiveDelphi

  50 Programas Fontes


  Produtos

Conheça Nossos Produtos

Copyright© 2001-2016 – Active Delphi – Todos os direitos reservados