Neste ano de 2013, dentre as recentes novidades anunciadas pela Embarcadero ao mundo Delphi, talvez a principal delas tenha sido a aquisição do AnyDAC, uma biblioteca de componentes de acesso a dados até então de propriedade da empresa DA-Soft Technologies. Conforme foi anunciado, o produto citado traz consigo uma nova gama de componentes para acesso aos dados de uma variedade de fontes, incluindo SGBDs (Ex: InterBase, Firebird, Oracle, MySQL etc.), servidores de aplicação DataSnap, além de drivers ODBC e dbExpress. Ao ser incorporado ao Delphi, o AnyDAC foi rebatizado para FireDAC. Este então é o tema do presente artigo, cujo enfoque se dará em seu lado mais prático no desenvolvimento de aplicações Delphi. Vale ressaltar que, apesar da mudança de nome, o “core” do produto permaneceu intacto neste momento, fazendo com que a curva de aprendizado para quem já o utilizava fosse zero. Para os que ainda não o conhecem, este artigo tem a intenção de ser o ponto de partida para sua efetiva utilização.

O acesso a dados é parte importante na construção de aplicações Delphi. Prova disso é que a ferramenta provê de forma nativa, uma série de opções para sua elaboração. Cada opção desta é refletida em uma biblioteca de componentes, ficando devidamente alocada na Tool Palette do IDE. Até o XE2, eram basicamente quatro as alternativas - BDE, dbExpress, InterBase Express e dbGo – no entanto, agora no XE3, este leque de opções ganha mais um elemento, o FireDAC que, de forma sucinta, pode ser definido como sendo uma biblioteca de acesso a dados universal.

O FireDAC pode ser considerado a edição da Embarcadero para a biblioteca de componentes de acesso a dados AnyDAC. Ele surge como uma forte opção no que se refere ao desenvolvimento de aplicação de banco de dados com Delphi, apresentando como pontos fortes sua facilidade de uso, alta performance e com recursos suficientes para atender as características gerais e particulares de cada SGBD suportado (Nota do DevMan 1).

Atualmente, o FireDAC suporta os seguintes SGBDs:

  • Advantage Database;
  • IBM DB2;
  • InterBase;
  • Firebird;
  • Microsoft Access;
  • Microsoft SQL Server;
  • MySQL;
  • Oracle;
  • PostgreSQL;
  • SQLite;
  • Sybase SQL Anywhere.

Atualmente o FireDAC é disponibilizado como um pacote singular que se integra ao Delphi. Para os usuários proprietários das edições Enterprise, Ultimate e Architect do XE3 (Nota do DevMan 2), ele é distribuído de forma gratuita, enquanto que para edições de menor calibre há um custo adicional. Fato é que nas futuras versões do Delphi o FireDAC já deverá acompanhar sua instalação, se tornando efetivamente parte integrante do IDE. Até lá, nada melhor do que já tirar proveito de sua atual disponibilidade, conhecendo todas as nuances que envolvem a utilização de suas classes, componentes e utilitários.

Em sua atual versão (XE3), o Delphi, como produto, possui cinco edições:

  • Starter Edition: edição de entrada, direcionada a estudos e construção de pequenos projetos. Por esta razão, não provê acesso a banco de dados e se restringe ao desenvolvimento para Win32;
  • Professional Edition: complementa a edição Starter com recursos para acesso local de dados e compilação para Win32, Win64 e Mac OS X;
  • Enterprise Edition: inclui todos os recursos da edição Professional, mais a parte de conectividade Client/Server e desenvolvimento de aplicações multicamadas (DataSnap);
  • Ultimate Edition: inclui tudo da edição Enterprise, com o adicional do DB Power Studio, que provê ferramentas voltadas às tratativas de banco de dados, tais como Rapid SQL, DB Optimizer e DB Change Manager;
  • Architect Edition: também inclui tudo da edição Enterprise, com o adicional do ER/Studio, uma ferramenta para modelagem e design de bancos de dados.

Conectando-se a um banco de dados Firebird

O Firebird é sem sombra de dúvidas um dos SGBDs mais utilizados em aplicações de banco de dados Delphi. Seu baixo custo de manutenção, simplicidade de uso, boa performance e, fundamentalmente, seu caráter gratuito, são algumas das principais características que o credenciam a tal posto. Ainda no Delphi 2010, em meio a suas novidades de lançamento, estava o novo driver dbExpress exclusivo para Firebird, que veio a atender um antigo e aclamado desejo da comunidade, que carecia de uma opção nativa ideal. Isto porque, até então, o desenvolvedor tinha basicamente duas alternativas para usar Firebird com dbExpress: recorrer a drivers de terceiro ou improvisar o driver para InterBase do dbExpress (o que causava certos transtornos em determinadas situações). Passado este momento, com a estabilização do driver citado, o Delphi ganha agora com o FireDAC, mais uma opção nativa para acesso a bancos de dados Firebird. Apesar de parecer algo natural e trivial num primeiro momento, o acesso a SGBD utilizando o componente de conexão (TADConnection) do FireDAC requer alguns tratamentos adicionais que, uma vez não realizados, podem causar certos transtornos ao desenvolvedor.

No TADConnection, uma definição padrão de conexão com um banco de dados envolve, basicamente, a configuração de duas de suas propriedades – DriverName e Params – num processo similar ao que é feito no TSQLConnection do dbExpress. Apenas para citar, em DriverName indica-se o nome do driver do FireDAC a ser utilizado, e em Params, os parâmetros da conexão (Ex: caminho do banco, usuário e senha do servidor, dialeto do banco, etc). O detalhe aqui fica por conta da ausência de um driver nominalmente específico ao Firebird, conforme mostra a Figura 1. Por esta razão, em um primeiro momento, é natural (e recomendada) a escolha pelo uso do driver IB que, em tese, visa atender tanto conexões para bancos InterBase quanto Firebird.

Lista de drivers para os bancos de dados suportados pelo FireDAC
Figura 1. Lista de drivers para os bancos de dados suportados pelo FireDAC

Tomando como exemplo a definição de uma conexão com o banco Employee, que acompanha a instalação do Firebird, o componente assume a configuração da Listagem 1.


object ADConnection1: TADConnection
   Params.Strings = (
     "DriverID=IB"      
     "Database=[caminho_instalação]\examples\empbuild\EMPLOYEE.FDB"
     "User_Name=SYSDBA"
     "Password=masterkey"
     "Protocol=TCPIP"
     "Server=localhost/3050")
   LoginPrompt = False
   ...
end
Listagem 1. Configuração da conexão - componente ADConnection

Neste momento, ainda em tempo de Design, ao se tentar ativar a conexão um erro é gerado, tal como mostra a Figura 2.

Lista de drivers para os bancos de dados suportados pelo FireDAC
Figura 2. Erro gerado ao tentar se conectar a um banco de dados Firebird, utilizando FireDAC

Na busca por soluções para se corrigir tal situação, sem o devido conhecimento, fica fácil imaginar que não há muito a se fazer, uma vez que o driver e os parâmetros de conexão foram devidamente configurados. Todavia, o grande detalhe pode ser constatado no editor de conexão do próprio componente, que é acessado através de um duplo-clique sobre o mesmo. A janela que se abre possui quatro guias, dentre as quais está a de nome “Info”. Nesta guia, são listadas em seções todas as informações relacionadas à conexão que está sendo estabelecida. Na seção “Client info” podem ser vistos então os detalhes relacionados à parte Client do banco, inclusive a biblioteca cliente que está sendo usada, tal como o exemplo a seguir, na Listagem 2.


================================
Client info
================================
Loading driver IB ...
Brand = Interbase
Client version = 1100019900
Client DLL name =   
C:\Users\Public\Documents\InterBase\redistInterBaseXE3\win32_togo\ibtogo.dll
Listagem 2. Client Info

Em “Client DLL name” fica nítida a “divergência” que está impossibilitando a estabilização da conexão com o banco de dados. Isto porque, por padrão, o FireDAC está tentando utilizar a biblioteca cliente ibtogo.dll do InterBase XE3, sendo que o correto, para este caso, seria a biblioteca fbclient.dll do próprio Firebird. Para que o FireDAC passe a utilizar a DLL cliente correta é necessário configurar seu arquivo de drivers denominado ADDrivers.ini, presente na pasta DB de sua instalação. De forma simples, este arquivo pode ser comparado ao dbxdrivers.ini do dbExpress.

Nativamente o arquivo ADDrivers.ini não traz conteúdo algum, dando mostras que toda a definição de drivers já parte de uma configuração padrão imposta pelo próprio framework. Todo e qualquer conteúdo adicionado a este arquivo irá então representar as customizações elaboradas pelo próprio desenvolvedor, mediante seu contexto de trabalho. No arquivo ADDrivers.ini há, basicamente, duas formas de se determinar a utilização da biblioteca correta por parte do driver. A primeira delas se faz simplesmente por sobrescrever a referida informação do próprio driver IB, tal como mostrado a na Listagem 3.


01 [IB]
02 VendorLib=C:\Program Files\Firebird\Firebird_2_5\bin\fbclient.dll
Listagem 3. Configuração do arquivo ADDrivers.ini

Simplesmente informamos ao seu parâmetro VendorLib o caminho completo da biblioteca cliente a ser utilizada. Apesar de funcional, esta forma restringe o driver IB a trabalhar apenas com bancos Firebird, uma vez que sobrescrevemos explicitamente seu parâmetro VendorLib. Isso impossibilitaria seu uso com bancos InterBase. Em vista dessa situação, a alternativa seria a definição de um novo driver virtual baseado no driver IB existente, mas com seu parâmetro VendorLib customizado para Firebird. Esta solução é então demonstrada na Listagem 4.


[FB]
BaseDriverID=IB
VendorLib=C:\Program Files\Firebird\Firebird_2_5\bin\fbclient.dll
Listagem 4. Configuração para Interbase e Firebird

Sendo assim, um novo driver virtual nomeado como FB foi definido, tendo como base o driver IB que é determinado no parâmetro BaseDriverID. Ao realizar este tipo de operação sobre o arquivo de drivers do FireDAC, uma boa prática é reiniciar o IDE certificando assim que o componente estará utilizando as informações mais recentes presentes no arquivo. Uma vez feito este procedimento o novo driver virtual é mostrado na lista de opções da propriedade DriverName, conforme mostra a Figura 3.

Novo driver virtual sendo mostrado na listagem de drivers do componente ADConnection
Figura 3. Novo driver virtual sendo mostrado na listagem de drivers do componente ADConnection

Uma vez realizado tais procedimentos, a conexão passará utilizar o driver do FireDAC já adequado a trabalhar com Firebird, fazendo uso da biblioteca cliente correta (Listagem 5).


================================
01 Client info
================================
02 Loading driver FB ...
03 Brand = Firebird
04 Client version = 205029900
05 Client DLL name = C:\Program Files\Firebird\Firebird_2_5\bin\fbclient.dll
Listagem 5. FireDAC utilizando a biblioteca correta após configuração

Fazendo o deploy de aplicações FireDAC

No Delphi, as aplicações de banco de dados comumente requerem algum tipo de cuidado no que diz respeito ao seu deploy. Ao se utilizar dbExpress e TClientDataSet, por exemplo, é necessário distribuir junto da aplicação alguns arquivos adicionais, tais como a DLL do driver DBX utilizado, bem como a biblioteca MIDAS.dll. Com o FireDAC isso não é muito diferente, sendo necessária algumas ações complementares para que a aplicação possa ser devidamente implantada (deploy) em outros ambientes que não o de desenvolvimento.

A primeira ação ocorre ainda em tempo de Design. Num teste simples podemos tomar como ponto de partida a conexão anteriormente criada. De forma complementar, um componente DataSet do FireDAC (tal como um TADQuery) pode ser utilizado para se recuperar os dados da tabela Customer do banco de dados, para que sejam mostrados em um TDBGrid conforme mostra a Figura 4. Até este momento, tudo está devidamente funcional. Todavia, ao se tentar executar a aplicação, uma Exception do FireDAC é disparada (Figura 5) interrompendo a sequência da execução.

Aplicação de exemplo em tempo de desenvolvimento
Figura 4. Aplicação de exemplo em tempo de desenvolvimento
Exception do FireDAC
Figura 5. Exception do FireDAC

Isto ocorre porque o FireDAC necessita de mais dois componentes (ou pelo menos da declaração de suas respectivas units) dentro do projeto. Como a própria mensagem sugere, o primeiro deles é um componente TADPhysIBDriverLink, que será o responsável pela conexão com a biblioteca cliente do banco de dados utilizado. Ele substitui a necessidade de se distribuir uma DLL externa do framework, tal como acontece no dbExpress. O outro componente em questão é o do tipo TADGUIxWaitCursor, que provê o controle sobre o cursor de espera de operações. Sua ausência causa, em Runtime, a exceção mostrada na Figura 6.

Exception do FireDAC
Figura 6. Exception do FireDAC

Por fim, pelo fato do acesso ao Firebird ter exigido algumas definições complementares no arquivo de drivers (ADDrivers.ini) do FireDAC, a presença deste se torna automaticamente obrigatória no deploy.

Operações com DataSets

Como não poderia deixar de ser, os DataSets providos pelo FireDAC oferecem recursos semelhantes aos providos por outros DataSets, tal como o TClientDataSet. Recursos estes que apesar de básicos, se tornam itens essenciais no desenvolvimento de qualquer aplicação de banco de dados no Delphi. Como forma de situar o leitor, a seguir são expostos, de forma prática, alguns destes recursos. Na medida do possível, será traçado um paralelo com outros recursos similares já providos de forma nativa pelo Delphi até então.

Ordenando registros em memória

De forma abrangente, todos os DataSets presentes na biblioteca do FireDAC proveem recursos para classificação local de dados. Isso significa dizer que, a partir de um conjunto de registros recuperados de uma fonte de dados, você pode ordená-los em memória num processo similar ao que é feito com ClientDataSet. Ainda com base nessa comparação, a forma padrão para se realizar a ordenação dos registros no FireDAC é também feita pelo uso da propriedade IndexFieldNames.

Tomando como base o exemplo anterior, onde foi utilizado um componente TADQuery, poderíamos centralizar a ação de ordenação de dados nos próprios títulos das colunas do DBGrid, que representam cada campo (Field) presente no DataSet. Sendo assim, no evento OnTitleClick (Listagem 6) do controle, teríamos um código da seguinte forma:


01 procedure TForm1.DBGrid1TitleClick(Column: TColumn);
02 begin
03    ADQuery1.IndexFieldNames := Column.FieldName;
04 end;
Listagem 6. Realizando a ordenação do DBGrid

Aqui, a propriedade IndexFieldNames recebe o nome do Field que será usado na ordenação que, para este caso, trata-se do próprio Field associado à coluna clicada. Indo além, é possível ainda passar à propriedade não somente a um, mas múltiplos campos, tornando a classificação das informações ainda mais abrangente, tal como mostrado na Listagem 7.

Listagem 7. Ordenação de múltiplos campos


ADQuery1.IndexFieldNames := "CAMPO_1;CAMPO_2;CAMPO_3;CAMPO_N";
Listagem 1. NOME

No FireDAC, por padrão, esta ordenação é realizada de forma ascendente. Para que este comportamento seja alterado e a ordenação passe a ser descendente, basta apenas acrescentar a indicação “:D” junto ao nome do campo passado à propriedade IndexFieldNames. A seguir, na Listagem 8, é mostrado um exemplo a partir do mesmo evento citado anteriormente.


procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
  ADQuery1.IndexFieldNames := Column.FieldName + ":D";
end;
Listagem 8. Alterando a forma de ordenação crescente para descendente

Os DataSets do FireDAC possibilitam ainda outra forma de se estabelecer essa classificação de dados, que é através do uso de índices pré-definidos, armazenados em sua propriedade Indexes. A Listagem 9 mostra um trecho de código do componente TADQuery, com um índice (de nome Ordenar Por Country e relacionado ao campo Country) definido em sua coleção Indexes.


object ADQuery1: TADQuery
    ...
    Indexes = <
      item
        Active = True
        Name = "Ordenar Por Country"
        Fields = "COUNTRY"
      end>
    ...        
end 
Listagem 9. Utilização de índices pré-definidos

Por fim, sua utilização se dá conforme a Listagem 10.


ADQuery1.IndexName := "Ordenar Por Country";
Listagem 10. Modo de uso do índice pré-definido

Filtrando registros em memória

No ClientDataSet, dentre seus recursos mais usuais, está o de filtro que permite uma sub-seleção dos dados presentes em seu cache. Isso quer dizer que a filtragem de dados acontece de forma local, sem envolver qualquer tipo de conexão com o banco de dados, num aspecto totalmente distinto do uso de instruções SQL. Na Listagem 11 é mostrado um código de exemplo que filtra os dados presentes em um ClientDataSet, através da passagem da condição de pesquisa, no formato string, para sua propriedade Filter. Em complemento, é atribuído o valor True à sua propriedade Filtered que, efetivamente, irá “filtrar” os dados em cache.


ClientDataSet1.Filter := "CUST_NO = 1001";
ClientDataSet1.Filtered := True; 
Listagem 11. Utilizando o filtro do ClientDataSet

De forma similar, os DataSets do FireDAC também fornecem este tipo de recurso. Num aspecto padrão, sua utilização se torna idêntica ao do ClientDataSet, conforme ilustrado na Listagem 12.


ADQuery1.Filter := "CUST_NO = 1010";
ADQuery1.Filtered := True;
Listagem 12. Filtro em cache no FireDAC

Seguindo por esta linha, além dos filtros sobre valores de dados, o FireDAC possibilita ainda a filtragem sobre os status dos registros. Sendo assim, a partir do conjunto de dados de um DataSet, é possível selecionar, por exemplo, somente aqueles que estão marcados como “modificado”, “incluído” ou “excluído” em cache. Tomando como base o componente TADQuery, por padrão, ele não mantém esse tipo de informação sobre os registros em cache, o que impossibilita o uso do recurso. Neste cenário, uma simples chamada ao seu método Post, por exemplo, faz com que toda e qualquer alteração realizada sobre um de seus registros seja imediatamente aplicada no banco. Ele não mantém um cache de atualizações, o que viabilizaria a aplicação de várias operações sobre o banco em um único lote, tal como acontece com ClientDataSet.

Para que o componente TADQuery passe a trabalhar com cache de atualizações, é necessário que sua propriedade CachedUpdates seja “ativada”, ou seja, marcada como True. Isso irá fazer com que toda e qualquer atualização de dados passe a ser adiada para uma futura aplicação em lote no banco de dados, fazendo com que o componente sinalize o devido status a cada registro inserido, modificado ou excluído. Assim, ao chamar o método Post, por exemplo, as alterações são efetivadas somente em memória. Para que as mesmas sejam aplicadas no banco, é necessário uma chamada complementar ao método ApplyUpdates, num processo semelhante ao que é feito com ClientDataSet.

Uma vez que o CachedUpdates está ativado, é possível então se realizar filtros sobre os status dos registros, através da propriedade FilterChanges. A seguir, na Listagem 13 é mostrado um exemplo simples de sua utilização, onde estão sendo filtrados os registros alterados, que ficam marcados no cache com o status de “modificado”.


ADQuery1.FilterChanges := [rtModified];
Listagem 13. Filtro de registros que sofreram alteração (em cache)

Localizando registros

Em complemento ao uso de filtros, estão os métodos padrão para localização de registros em DataSets do FireDAC. Apesar de haver inúmeros métodos e formas para este fim, podemos inicialmente destacar dois deles, em razão de sua simplicidade e eficácia. O primeiro a ser mencionado é o Locate, já habitual de outros DataSets presentes no Delphi. Sua utilização aqui se dá de forma idêntica ao tradicional, tal como mostrado na Listagem 14.


ADQuery1.Locate("CUSTOMER", "D", [loPartialKey, loCaseInsensitive]);
Listagem 14. Locate com DataSets do FireDAC

Nesta chamada, está sendo realizada uma busca com base no campo CUSTOMER, cujo valor seja iniciado com a letra D. Vale lembrar que o Locate efetivamente não retorna o valor do registro em si, apenas direciona o ponteiro para a primeira ocorrência encontrada.

Outro método de localização a ser citado é o LocateEx, que pode ser considerado uma evolução do Locate uma vez que permite também a utilização de expressões como critério de busca, e não somente simples valores. Na Listagem 15 são mostradas duas situações de uso do LocateEx, cujo resultado será o mesmo do exemplo anterior, só que agora fazendo uso do método referido, através do uso de valores e expressão.


// Baseado em valor
ADQuery1.LocateEx("CUSTOMER", "D", [lxoPartialKey, lxoCaseInsensitive]);

// Baseado em expressão
ADQuery1.LocateEx("CUSTOMER like ""D%""", [lxoPartialKey, 
lxoCaseInsensitive]); 
Listagem 15. Utilizando o LocateEx

Trabalhando com campos calculados

Via de regra, o uso de DataSets em aplicações de banco de dados aumenta a gama de recursos disponíveis ao desenvolvedor, em meio ao processo de desenvolvimento. Dentre estes, estão os campos calculados, que são elementos virtuais definidos pelo próprio programador, visando atender alguma necessidade pontual da aplicação. O grande diferencial dos campos calculados, sem dúvida alguma, está na flexibilidade da composição de seus valores. Em outras palavras, seus valores não possuem uma relação direta com o banco de dados, o que dá margens para uma ideal customização dessas informações. Num exemplo clássico, podemos ter um campo calculado para o Sub-Total de uma venda, cujo valor é o resultado da multiplicação dos valores das colunas Quantidade e Valor do Produto. Internamente, todo este processo é feito de maneira inteligente e rápida, todo em memória.

Nos DataSets do FireDAC, a forma mais tradicional de se definir campos calculados é diretamente em seu FieldsEditor. Dito isto, aproveitando o exemplo de uso da tabela Customer, podemos criar um campo do tipo Calculated que será a junção das informações de outros dois campos do DataSet: City e Country. A Figura 7 exibe a janela de definição de um novo Field no DataSet, do tipo Calculated.

Criando campo calculado
Figura 7. Criando campo calculado

Para o “cálculo” do valor do campo, os DataSets do FireDAC, assim como outros DataSets tradicionais do Delphi, possuem um evento exclusivo – OnCalcFields. Portanto, é nele que iremos escrever a instrução de formação do valor do campo, tal como a Listagem 16.


procedure TForm1.ADQuery1CalcFields(DataSet: TDataSet);
begin
   ADQuery1CALC_CITY_COUNTRY.AsString := ADQuery1CITY.AsString + " - " + 
        ADQuery1COUNTRY.AsString;
end;
Listagem 16. Escrevendo campos calculados

Apenas para comentar, no código, simplesmente atribuímos ao campo calculado criado o valor do campo CITY, concatenado com o valor do campo COUNTRY. O resultado disso pode ser visto em destaque na Figura 8.

Criando campo calculado
Figura 8. Criando campo calculado

Conforme pôde ser visto, campos do tipo Calculated são definidos em nível de registro, ou seja, para cada linha do DataSet, seu valor é calculado. Em complemento a isso, é possível se definir campos calculados em nível de conjunto de registros, os quais são chamados de agregados (AggregateFields). Num exemplo trivial, podemos ter um campo deste tipo para sumarizar os valores de determinada coluna (preço, por exemplo), de todos os registros do DataSet. Sua definição básica envolve a criação de um novo campo do tipo Aggregate, aos mesmos moldes do que foi feito para o campo Calculated, bem como algumas configurações no DataSet (AggregatesActive = True) e nas propriedades do Field criado, conforme mostrado na Listagem 17.


object ADQuery1AG_COUNT_CUST_NO: TAggregateField
  FieldName = "AG_COUNT_CUST_NO"
  Active = True
  Expression = "COUNT(CUST_NO)"
end
Listagem 17. Configurando um campo Aggregate

Neste trecho, FieldName representa o nome definido ao campo agregado, e a propriedade Expression contém a expressão a ser utilizada para a determinação de seu valor. Numa exemplificação simples, neste caso apenas está sendo feita uma contagem (COUNT) do campo CUST_NO, que irá resultar no total de registros presentes no DataSet, tal como um RecordCount.

Definindo um relacionamento Master-Detail com DataSets

Ainda citando as aplicações de banco de dados, é comum as situações onde se faz necessária a definição de um relacionamento mestre-detalhe entre os DataSets envolvidos. Olhando pelo lado nativo, a definição deste cenário em meio a utilização de componentes dbExpress e ClientDataSet já pode ser considerado algo natural ao desenvolvedor. Com a chegada do FireDAC, apesar do cenário se manter o mesmo, os elementos envolvidos são outros. Sendo assim, torna-se importante o conhecimento de como conseguir os mesmos resultados através do uso de elementos desta nova biblioteca. A intenção aqui é fazer com que ao se apontar para um registro num DataSet “Master”, todos os seus registros relacionados sejam automaticamente carregados em outro DataSet “Detail”. Para uma exemplificação simples, podemos utilizar o próprio banco Employee do Firebird, aproveitando o relacionamento existente entre as tabelas Employee, que farão o papel de estrutura Mestre, e SalaryHistory, para a parte de Detalhe.

No FireDAC há basicamente duas formas de se definir este tipo de relacionamento entre seus DataSets: baseado em parâmetros ou baseado em série. O detalhe aqui é que ambas variam sobre como se dará a configuração do DataSet “Detail”, permanecendo o DataSet “Master” inalterado em ambos os casos.

1º forma: Parameter based

Na forma baseada em parâmetro, a consulta SQL presente no DataSet “Detail” possui uma cláusula Where, onde seu campo de relacionamento com a estrutura “Master” (EMP_NO, neste caso) recebe o valor de um parâmetro de mesmo nome. No exemplo proposto, a instrução SQL ficaria como na Listagem 18.


select
* from SALARY_HISTORY where EMP_NO = :EMP_NO
Listagem 18. SQL de um mestre detalhe

Para que o valor do parâmetro seja passado de forma automática do DataSet “Master” para o DataSet “Detail”, é necessário que seja atribuído à sua propriedade MasterSource, um componente TDataSource devidamente ligado ao DataSet “Master”. Isto é o suficiente para que o relacionamento seja estabelecido, tal como mostra a Figura 9.

Relacionamento Mestre-Detalhe com FireDAC
Figura 9. Relacionamento Mestre-Detalhe com FireDAC

2º forma: Range based

Já na forma baseada em série, os valores dos campos do DataSet “Master” são aplicados a uma série de registros do DataSet “Detail”, que deverá possuir um índice ativo. Na prática, tem-se a mesma estrutura de componentes da forma anterior, mas com os seguintes diferenciais nas configurações do DataSet “Detail”:

  • A instrução SQL utilizada é mais abrangente, não dependendo de parâmetros explícitos. Assim, a instrução anteriormente usada seria algo como: “select * from SALARY_HISTORY”
  • Em sua propriedade MasterFields deve-se indicar o campo do DataSet “Master” que será utilizado no relacionamento. Para o exemplo proposto, trata-se do campo EMP_NO;
  • Conforme mencionado anteriormente, o DataSet “Detail” precisa de um índice ativo, relativo ao campo de relacionamento. Sendo assim, em sua propriedade IndexFieldNames, deve-se escolher o próprio campo EMP_NO de sua estrutura;

Por fim, em termos práticos, o resultado obtido deve ser o mesmo mostrado na Figura 9, ou seja, ao se navegar pelos registros da tabela Employee (Master), automaticamente vão sendo mostrados seus registros relacionados na tabela SalaryHistory. Posto isto, a escolha por uma ou outra abordagem é determinada pelas características e funcionalidades providas por cada uma, conforme listado a seguir.

Parameter based

  • Permite se limitar o número de registros a serem retornados pela consulta SQL do DataSet “Detail”;
  • Os dados mantidos pelo DataSet “Detail” são mais atualizados;

Range based

  • As operações realizadas sobre o DataSet “Master” são mais otimizadas, no que diz respeito à carga de trabalho sobre o SGBD;
  • Permite se trabalhar com Cached Updates centralizado;
  • Permite operar em modo “offline”.

Definindo consultas SQL no QueryEditor do TADQuery

No FireDAC é comum o uso do componente TADQuery para as situações que envolvam consultas SQL a serem realizadas sobre um banco de dados. Conforme visto anteriormente, é nele que definimos, por exemplo, o comando “select” a ser utilizado numa estrutura de cadastro. Para tal, ele dispõe de uma propriedade denominada SQL, específica para o armazenamento dessa instrução. Por padrão, ao acioná-la, um simples editor de texto é aberto (Figura 10) para que o desenvolvedor escreva a instrução desejada. Apesar de útil, este recurso é bastante limitado. No pior das hipóteses, corremos o risco de digitarmos errado o comando SQL, causando um “crash” na aplicação, devido a um erro de sintaxe. Para melhorar este cenário, o TADQuery provê de um recurso adicional denominado QueryEditor que, entre outras coisas, permite testar a instrução que está sendo informada, bem como configurar os parâmetros envolvidos, caso hajam. Ele fica disponível no menu de contexto do próprio componente e, uma vez acionado, sua janela é mostrada em tela (Figura 11).

Ao se definir uma consulta SQL no QueryEditor, ela já é automaticamente atribuída à propriedade SQL do componente. O detalhe aqui fica por conta da possibilidade de execução imediata da mesma, para testes de sintaxe e qualidade. Os dados retornados pela consulta são então exibidos na guia RecordSet, bem como a estrutura dos campos (ex: nome e tipo de dado) é mostrada na guia Structure (Figura 12).

Editor SQL
Figura 10. Editor SQL
QueryEditor
Figura 11. QueryEditor
Estrutura de campos sendo mostrada no QueryEditor
Figura 12. Estrutura de campos sendo mostrada no QueryEditor

Conclusão

Na comunidade, o reflexo imediato causado pelo anúncio da aquisição do AnyDAC (FireDAC) por parte da Embarcadero foi de muita contestação, argumentada pelo fato da já existência de uma solução nativa similar, que é o dbExpress. Polêmicas a parte, olhando pelo lado positivo, esta mais nova aquisição serve para certificar a constante evolução que a Embarcadero vem se propondo a realizar para o Delphi. A inclusão do FireDAC em seu contexto significa a abertura de novas possibilidades de desenvolvimento, bem como um aumento de seu já extenso quadro de recursos, no que diz respeito a acesso a dados.

Qual será a tendência daqui pra frente, dbExpress ou FireDAC? Como se dará a evolução de uma e outra biblioteca? Uma provável migração vale a pena? Inevitavelmente, essas e outras perguntas irão surgir neste momento, contudo, só o tempo é que poderá responder cada uma delas de forma efetiva. Pessoalmente falando não vejo motivos, por exemplo, para quem já tem toda uma bagagem feita em cima do dbExpress, almejar uma migração para FireDAC neste momento. Ambas as tecnologias dividirão terreno por um bom tempo ainda e a decisão por uma ou outra se dará, fundamentalmente, por questões de projeto e negócio.


Links Úteis sobre Delphi


Saiba mais sobre Delphi ;)

  • Guias Delphi: Aqui você encontra os Guias de estudo da linguagem Delphi. Descubra como dominar o Delphi, desde o recurso mais básico ao mais avançado. Escolha o seu!
  • Carreira Programador Delphi: Neste guia de estudos você encontra os conteúdos que precisará para se tornar um programador Delphi completo. Confira a sequência de cursos e exemplos que te guiarão do básico ao avançado em Delphi.
Referencias: Delphi Site Oficial