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:
- OPEN
DATABASE _Samples + "Northwind\Northwind.dbc"
- usamos
um commando nativo do VFP para abrir o banco de dados Northwind.dbc.
- loCAClientes
= CREATEOBJECT("CursorAdapter")
- instanciamos a classe
CursorAdapter nativa do Visual FoxPro.
- 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"
-
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.
-
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.
-
Agora especificamos
qual é a tabela que deve ser alterada na origem de dados:
loCAClientes.Tables
= "Customers"
-
Aqui indicamos
qual é o campo chave da tabela:
loCAClientes.KeyFieldList
= "CustomerID"
-
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"
-
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