sexta-feira, 20 de abril de 2012

CursorAdapter com Visual FoxPro



Desde o princípio o FoxPro é famoso por seu poder de acesso a dados. Inicialmente, impressionava pela velocidade e facilidade em fazê-lo. Hoje em dia, há muito mais que isso. A flexibilidade sem dúvida impressiona muito mais. Teoricamente diz-se que através do Visual FoxPro pode-se acessar qualquer tipo de fonte de dados, desde que essa tenha conectividade através de ODBC, OLEDB ou ADO. No entanto, praticamente qualquer linguagem é capaz de fazê-lo também. Mas na prática temos visto que o Visual FoxPro é capaz de processar dados remotos (de outras fontes que não seja o DBC) com uma performance muito superior a outras linguagens.

No Visual FoxPro 8.0 foi introduzido um novo conceito de acesso a dados. Trata-se de uma classe orientada a objetos chamada CursorAdapter. 
 
Através da classe CursorAdapter, que traduzido para o português quer dizer adaptador de cursores, podemos trabalhar com dados das mais diversas fontes sem nos preocupar muito com os detalhes da tecnologia do banco de dados remoto, ou mesmo em aprender os recursos do Driver ODBC ou OLEDB que provêem acesso à fonte de dados remota.
A classe encapsula o conhecimento sobre como transformar os dados remotos em dados locais do Visual FoxPro. Isso mesmo! O dado remoto é transformado em um cursor, o que facilita o trabalho do desenvolvedor. Quando da necessidade de enviar os dados do cursor para a fonte remota, a classe CursorAdapter sabe muito bem o que fazer. Prepara os dados, e envia para a fonte, assegurando que sejam gravados corretamente.

Antes da versão 8.0 do VFP precisávamos escrever nossas próprias classes de acesso a dados para trabalhar com fontes de dados externas. Geralmente utilizava-se objetos RecordSet da biblioteca ADO para acesso orientado a objetos. Para acesso através de programação não OOP, utilizava-se outros recursos como Remote Views e SQL Pass-Through.

Um aplicativo construído com Remote Views usando um banco de dados MS SQL Server, se necessário alterar para uso com Oracle teria no mínimo que refazer as Views. Com o uso de CA’s (CursorAdapter’s) as alterações seriam bem menos traumáticas. Como as CA’s são classes OOP, é totalmente possível criarmos classes mais especializadas capazes de agregar novos recursos e até mesmo novas funcionalidades, fazendo com que o acesso a dados em VFP continue sendo insuperável por qualquer outra ferramenta.

Através da classe CursorAdapter podemos acessar dados das seguintes fontes de dados:
. Nativa (DBF/DBC)
. ODBC
.
ADO
. XML

Vejamos o que significa cada tipo de fonte de dados:
NATIVE -Indica que o objeto CursorAdapter trabalhará com dados nativos do Visual FoxPro (banco DBC/tabelas DBF).
ODBC - Indica que a classe CursorAdapter trabalhará com fontes de dados que serão acessadas através de drivers ODBC. É possível acessar dados remotos numa rede ou fora dela.
ADO - Indica que a classe CursorAdapter usará a biblioteca ADO para acessar a fonte de dados. A biblioteca ADO trabalha com biblioteca de drivers OLEDB, que são mais atualizados que os drivers ODBC.
XML - Indica que a classe CursorAdapter trabalhará com documentos XML como fonte de dados.

Quando usando fontes de dados ODBC e ADO, necessita-se de uma conexão estabelecida previamente com o banco de dados.
Para ODBC, podemos estabelecer a conexão através das funções SQLCONNECT() e SQLSTRINGCONNECT(). Veja posteriormente ainda neste capítulo as definições para estas funções. 
 
Principais PEM's da classe CursorAdapter
Antes de prosseguirmos, vamos conhecer as principais propriedades, eventos e métodos da classe CursorAdapter. A partir do conhecimento das PEM's desta classe, poderemos melhor aproveita-la. 
 
Eventos do Objeto CursorAdapter
Evento Descrição
AfterCursorAttach
Ocorre imediatamente depois que o método CursorAttach é executado.
AfterCursorClose
Ocorre depois que o objeto CursorAdapter é fechado
AfterCursorDetach
Ocorre imediatamente depois que o método CursorDetach é executado.
AfterCursorFill
Ocorre depois que o método CursorFill é executado.
AfterCursorRefresh
Ocorre imediatamente após o método CursorRefresh ser executado.
AfterCursorUpdate
Ocorre depois que qualquer dado do cursor seja atualizado através da função TABLEUPDATE().
AfterDelete
Ocorre sempre depois que um comando DELETE seja executado.
AfterInsert
Ocorre sempre depois que um comando INSERT é executado.
AfterUpdate
Ocorre imediatamente depois que uma operação de atualização é executada para um registro.
BeforeCursorAttach
Ocorre imediatamente antes que o objeto CursorAdapter tente unir (attach) um cursor. Você pode usar este evento para executar todas as operações necessárias antes de unir (attach) o cursor ou tabela, determinar um apelido (alias) para a união (attach), e assim por diante.
BeforeCursorClose
Ocorre imediatamente antes que um cursor se feche. Você pode usar este evento para executar todas as operações necessárias antes de fechar um cursor ou tabela, e assim por diante.
BeforeCursorDetach
Ocorre antes do método CursorDetach ser executado.
Você pode executar este evento para executar todas as operações necessárias antes de desanexar o cursor ou a tabela.
BeforeCursorFill
Ocorre imediatamente antes do método CursorFill ser executado.
BeforeCursorRefresh
Ocorre antes do método CursorRefresh ser executado.
BeforeCursorUpdate
Ocorre imediatamente antes da função TABLEUPDATE() ser executada.
BeforeDelete
Ocorre imediatamente antes que um comando de deleção de registro seja executado.
BeforeInsert
Ocorre imediatamente antes de um comando de inserção de registro ser executado.
BeforeUpdate
Ocorre imediatamente antes de um comando de atualização para um registro.
Principais Propriedades do Objeto CursorAdapter
Propriedade Descrição
Alias
Especifica um apelido para a tabela a ser gerada pelo objeto CursorAdapter.
AllowDelete
Especifica se os dados apagados num cursor são submetidos para a origem de dados.
AllowInsert
Especifica se os dados inseridos no cursor são enviados para a origem de dados.
AllowUpdate
Especifica se os dados modificados num cursor associado a um objeto CursorAdapter são enviados para a origem de dados.
ConversionFunc
Especifica funções para conversão de dados.
CursorSchema
Especifica o formato de dados para o cursor local gerado.
DataSource
Especifica a conexão com a origem de dados.
DataSourceType
Especifica o tipo de origem de dados.
KeyFieldList
Especifica a lista de campos chave para o CursorAdapter.
SelectCmd
Especifica o comando para recuperar (consultar) dados da origem de dados.
SendUpdates
Especifica se os dados resultantes de uma consulta em um objeto CursorAdapter são enviados para a origem de dados.
Tables
Especifica quais tabelas devem ser atualizadas para operações de inserção, alteração ou remoção quando um objeto CursorAdapter aceita atualizações. Quando mais de uma tabela, separa-las por vírgula.
UpdatableFieldList
Lista de campos atualizáveis.
UpdateNameList
Lista contendo os nomes dos campos atualizáveis em pares identificando o campo na tabela loca e o respectivo campo na tabela remota.
Principais Métodos do Objeto CursorAdapter
Método Descrição
AutoOpen
Executa o método CursorFill sem passar nenhum parâmetro padrão. Quando o objeto CursorAdapter está dentro do ambiente de dados de um formulário, o ambiente de dados chama o método AutoOpen automaticamente dentro do método OpenTables do ambiente de dados.
CursorAttach
Anexa um cursor existente à uma instância já existe de um objeto CursorAdapter.
CursorDetach
Libera um cursor anexado à uma instância do objeto CursorAdapter sendo executado.
CursorFill
Executa o comando da propriedade SelectCmd de acordo com o DataSource selecionado, cria um cursor com os dados recuperados, executa a conversão de dados necessária de acordo com as propriedades DataSourceType e CursorSchema.
CursorRefresh
Atualiza um cursor com os dados atuais da origem de dados.
Acessando dados nativos (DBC/DBF) com CursorAdapter
Uma boa forma de iniciar os estudos da classe CursorAdapter é utilizando os dados nativos do Visual FoxPro. Sim, aqueles que geralmente usamos comandos xBase como OPEN DATABASE, USE, etc., para abrir, o banco de dados.
Vejamos o exemplo da listagem 1 a seguir:
Listagem 1:
LOCAL loCAClientes AS CursorAdapter
OPEN DATABASE _Samples + "Northwind\Northwind.dbc"
*!* Instancia a classe CursorAdap
loCAClientes = CREATEOBJECT("CursorAdapter")
loCAClientes.DataSourceType = "NATIVE" && Banco nativo
loCAClientes.DataSource = "" && Origem de dados
loCAClientes.Alias = "Clientes"&& Define o Alias
loCAClientes.SelectCmd = "SELECT * FROM Customers"
IF loCAClientes.CursorFill()
BROWSE FONT 'Courier New',12 && Exibe os dados da tabela
ELSE
MESSAGEBOX("Cursor não criado!",0+16,"Erro")
ENDIF
CLOSE DATABASES ALL
Ao executar o exemplo acima teremos o seguinte resultado:
Figura 1 - Cursor criado pelo objeto loCAClientes
Examinando o código da listagem 1 podemos verificar as seguintes ações:
  1. OPEN DATABASE _Samples + "Northwind\Northwind.dbc" - usamos um commando nativo do VFP para abrir o banco de dados Northwind.dbc.
  2. loCAClientes = CREATEOBJECT("CursorAdapter") - instanciamos a classe CursorAdapter nativa do Visual FoxPro.
  3. Definimos as propriedades mínimas para o funcionamento de nossa consulta:
loCAClientes.DataSourceType= "NATIVE" && Banco nativo
loCAClientes.DataSource = "" && Origem de dados
loCAClientes.Alias = "Clientes" && Define o Alias
loCAClientes.SelectCmd = "SELECT * FROM Customers"
  1. Finalmente executamos o método responsável por enviar a solicitação da consulta ao banco de dados e criar o cursor resultante:
loCAClientes.CursorFill()
Como é notório, não é nada complicado o uso básico da classe CursorAdapter. É importante lembrar que a estamos utilizando a partir de um PRG. Para uso em um formulário há alguns cuidados a tomar que serão tratados posteriormente, em outro artigo.
Embora o cursor gerado com o código da listagem 1 seja de leitura e escrita, os dados alterados não serão enviados para a origem de dados, ou seja, nenhuma atualização será realizada nos dados originais. A seguir, veremos como tornar a origem de dados atualizável.
Atualizando os dados na Origem de Dados
No exemplo anterior fizemos uma consulta a uma origem de dados nativa. Embora o cursor resultante seja de leitura e escrita, qualquer alteração que fizermos em seus dados, não será enviada para a origem de dados. Para que essas modificações reflitam no banco de dados de origem é necessário preencher corretamente as propriedades SendUpdates, Tables, KeyFieldList, UpdatableFieldList, UpdateNameList.
Na próxima listagem de código, denominada listagem 2, partimos do código da listagem 1, acrescentando as linhas de código necessárias para enviar os dados alterados para a origem de dados.

Listagem 2:
LOCAL loCAClientes AS CursorAdapter
OPEN DATABASE _Samples + "Northwind\Northwind.dbc"

*!* Instancia a classe CursorAdapter
loCAClientes = CREATEOBJECT("CursorAdapter")
loCAClientes.DataSourceType = "NATIVE" && Banco nativo
loCAClientes.DataSource = "" && Origem de dados
loCAClientes.Alias = "Clientes"&& Define o Alias
loCAClientes.SelectCmd = "SELECT * FROM Customers"
*!* As linhas a seguir tornam a origem de dados atualizável
loCAClientes.SendUpdates = .T.
loCAClientes.Tables = "Customers"
loCAClientes.KeyFieldList = "CustomerID"
loCAClientes.UpdatableFieldList="CompanyName, ContactName, Country"
loCAClientes.UpdateNameList = "CustomerID Customers.CustomerID, "+;
"CompanyName Customers.CompanyName, "+;
"ContactName Customers.ContactName, "+;
"Country Customers.Country"
*!* As linhas a seguir tornam a origem de dados atualizável
IF loCAClientes.CursorFill()
BROWSE FONT 'Courier New',12 && Exibe os dados da tabela
ELSE
MESSAGEBOX("Cursor não criado!",0+16,"Erro")
ENDIF
CLOSE DATABASES ALL

A diferença do código da listagem 2 em relação do código da listagem 1 são as linhas de código a seguir:

*!* As linhas a seguir tornam a origem de dados atualizável
loCAClientes.SendUpdates = .T.
loCAClientes.Tables = "Customers"
loCAClientes.KeyFieldList = "CustomerID"
loCAClientes.UpdatableFieldList="CompanyName, ContactName, Country"
loCAClientes.UpdateNameList = "CustomerID Customers.CustomerID, "+;
"CompanyName Customers.CompanyName, "+;
"ContactName Customers.ContactName, "+;
"Country Customers.Country"

Observe que as propriedades SendUpdates, Tables, KeyFieldList, UpdatableFieldList, UpdateNameList que foram citadas anteriormente como sendo pré-requisito para que os dados sejam atualizados na origem de dados estão presentes nessas linhas de código e consequentemente os dados podem ser atualizados na origem de dados. Para confirmar o que estou afirmando aqui, o melhor a fazer é executar o código e realizar qualquer alteração sobre os dados das colunas CompanyName, ContactName e Country. Qualquer alteração realizada em qualquer outra coluna não será enviada para a origem de dados, uma vez que estas não estão listadas nas propriedades UpdatableFieldList e UpdateNameList. Veja a figura 2 com dados alterados na coluna CompanyName, onde acrescentei Brazil ao final. Para que a alteração seja enviada para a origem de dados basta movimentar o ponteiro do registro para o próximo registro.

Figura 2 - Dados alterados no cursor são enviados para a origem de dados
Analisemos agora o que cada linha de código adicionada neste PRG realiza efetivamente.

  1. Na linha de código a seguir, dizemos ao objeto loCAClientes que qualquer alteração deve ser enviada para a origem de dados. No entanto, o sucesso do envio dessas alterações dependerá da definição das demais propriedades que discutiremos a nos próximos tópicos:
loCAClientes.SendUpdates = .T.
  1. Agora especificamos qual é a tabela que deve ser alterada na origem de dados:
loCAClientes.Tables = "Customers"
  1. Aqui indicamos qual é o campo chave da tabela:
loCAClientes.KeyFieldList = "CustomerID"
  1. A seguir passamos a lista de campos que queremos que sejam atualizáveis na origem de dados. Cada campo é separado por vírgula:
loCAClientes.UpdatableFieldList="CompanyName, ContactName, Country"
  1. A última propriedade é responsável por fazer um mapeamento dos campos do cursor gerado pelo objeto CursorAdapter com os campos da tabela na origem de dados, onde o campo do lado esquerdo do par representa o campo do cursor e a seqüência nometabela.nomecampo representa a tabela e o campo na origem da dados:
loCAClientes.UpdateNameList= "CustomerID Customers.CustomerID, "+;
"CompanyName Customers.CompanyName, "+;
"ContactName Customers.ContactName, "+;
"Country Customers.Country"

Até aqui nada complicado. Diria que torna-se um pouco tedioso e meio repetitivo a tarefa de informar os dados das propriedades UpdatableFieldList e UpdateNameList, mas fora isso, o processo é bastante simples.

Fonte: http://imasters.com.br/artigo/3958/desenvolvimento/acesso-a-dados-com-a-classe-cursoradapter
Creditos: Nilton Paulino

Nenhum comentário:

Postar um comentário