ADO - Trabalhando com Recordsets sem uma base de dados


Qual seria sua reação se alguém dissesse que pode trabalhar com Recordsets ADO sem utilizar qualquer fonte de dados externa ?  Espanto ? Descrença ?  Curiosidade ? ...

Qualquer que seja a sua reação vou logo dizer que isto é perfeitamente possível e viável e com algumas vantagens . Quer saber quais são elas ?

  1. Você não precisa criar um banco de dados ( Uau... )
  2. Como o seu sistema não depende de uma base de dados externas ele fica mais portátil
  3. Você não tem que se preocupar em como se conectar a uma base de dados ( ela não existe .. :-)
  4. A quantidade de código fica reduzida e a manutenção fica mais fácil
  5. Sua aplicação fica com um tamanho menor e necessita de menos recursos para ser executado.
  6. Você usa todo o seu conhecimento sobre o modelo de objeto ADO

Bem , se você ainda esta incrédulo , e , é daqueles que precisa ver para crer , vamos mostrar uma aplicação completa com um recordset ADO sem usar um banco de dados. ( se quiser pode dar uma olhada no artigo - Retornando dados com GetRows - onde já arranhamos o assunto...)

Vamos criar um pequeno programa , uma agenda pessoal , para armazenar os endereços dos amigos , parentes , etc... Estaremos trabalhando com as opções de incluir , alterar e excluir os registros do nosso arquivo de dados, tudo isto sem usar um banco de dados...

Criando a aplicação - Agenda

Você deve estar se perguntando - Como vamos usar um Recordset sem um banco de dados ?

Se você ainda não sabe , a ADO permite utilizar um recordset desconectado . É este conceito que vamos usar. Podemos desconectar e mais tarde fazer a conexão com  uma base de dados , mas este não vai ser nosso caso. Simplesmente vamos usar o recordset desconectado. Para definir um recordset desconectado podemos dizer que: "Um recordset desconectado é um recordset do lado do cliente que não tem uma conexão ativa a uma fonte de dados ou banco de dados."

Só para você ter uma idéia da utilidade desta técnica , imagine um servidor de banco de dados que pode lidar com apenas um certo número limitado de conexões ativas ao mesmo tempo. Assim quando um aplicativo precisa esperar a entrada do usuário ou qualquer outra ação do usuário , porque manter a conexão aberta por todo este tempo ?

Você pode , no caso acima, recuperar os dados de uma fonte de dados , armazenar os dados em um recordset e desconectar o recordset da fonte de dados para libera recursos da conexão.  O aplicativo altera os dados ou incluir novos dados ao recordset e depois se reconecta e a fonte de dados e escreve as mudanças ocorridas. Entendeu ???

As duas principais técnicas para criar um recordset desconectado são :

  1. Prepare e abra um recordset do lado do cliente e preencha-o com os dados do banco de dados; A seguir desconecte o Recordset ( veja abaixo ) .
  2. Prepare um recordset do lado do cliente e apos definir as propriedades dos campos use o método Open para que o recordset seja preenchido com os registros.

A primeira coisa a fazer para gerar um recordset (rsagenda)  desconectado é : 

  1. criar uma variável objeto  -  Set rsagenda = ADODB.Connection  
  2.  a seguir definir a conexão ativa  através da propriedade ActiveConnection  para Nothing  -   Set ActiveConnection =  Nothing
  3. Definir o tipo do cursor como estando do lado do Cliente - CursorLocation = adUseClient

Pronto , já temos nosso recordset desconectado e pronto para ser usado. Precisamos no entanto fazer os ajustes finais , os quais sejam :

  1. Definir o tipo de bloqueio - LockType = adLockBatchOptimistic - indicando que as atualizações no recordset ocorrerão no modo otimista e em lote. ( durante a edição outros usuários não poderão alterar o conteúdo do registro

E a estrutura do Recordset ? de onde virá ?

Bem . como não estamos usando um banco de dados vamos ter que criar a estrutura do recordset. Para fazer isto usamos o método Append da coleção Fields e incluímos a definição de cada campo ao recordset. Para fazer isto vamos precisar conhecer o nome , tamanho e o tipo de dados de cada campo.

A sintaxe para para o método Append é :

objetoRecordset.Fields .Append NomeCampo , TipoCampo ,  TamanhoCampo , Atributos

O nome e o tamanho dos campos são definidos com base nas informações que desejamos armazenar. Assim, para o nosso caso , vamos armazenar : o nome , endereço ,cidade , cep , uf , telefone e email. Podemos definir o nome e o tamanho conforme a tabela abaixo :

Nome

Tamanho

AgNome

50

AgEndereco 50
AgCidade 40
AgCep 15
Aguf 2
Agtelefone 15
Agemail 250

E o tipo de dados , como vamos definir ?  Abaixo temos os principais tipos de dados suportados  na ADO :

Constant Description
adBinary Um valor binário (DBTYPE_BYTES).
adBoolean Um valor Boleano (DBTYPE_BOOL).
adBSTR Um caractere string terminado em null-(Unicode) (DBTYPE_BSTR).
adChar Um valor  String fixo. (DBTYPE_STR).
adCurrency Um valor monetário (DBTYPE_CY).
adDate Um valor Data (DBTYPE_DATE). 
adDBDate Um valor Data (yyyymmdd) (DBTYPE_DBDATE).
adDBTime Um valor para  horas (hhmmss) (DBTYPE_DBTIME).
adDecimal Um valor numérico exato com precisao defnida.(DBTYPE_DECIMAL).
adDouble Valores de precisao dupla (DBTYPE_R8).
adEmpty Um valor não definido (DBTYPE_EMPTY).
adInteger Um inteiro de 4 bytes (DBTYPE_I4).
adNumeric Um valor numerico (DBTYPE_NUMERIC).
adSingle Precisão simples (DBTYPE_R4).
adVarChar Um valor String (Parameter object only).
adVariant Um valor Variant (DBTYPE_VARIANT).

Como no nosso exemplo todos os campos são do tipo Texto podemos usar então o tipo de dado adVarChar ou adBSTR . Vamos usar advarChar.

O parâmetro Atributos ( Attributes ) é opcional e define atributos para os novos campos : EX: Conter valores NULL - adFldMaybeNull. O valor padrão é adFldDefault .

Nosso recordset será criando conforme o código a seguir:

   With .Fields
           .Append "Nome", adVarChar, 50
           .Append "Endereco", adVarChar, 50
           .Append "Cidade", adVarChar, 40
           .Append "Cep", adVarChar, 15
           .Append "UF", adVarChar, 2
           .Append "telefone", adVarChar, 15
           .Append "email", adVarChar, 250
       End With

]E como fazemos para salvar o Recordset ?  

Simples,  use o método Save do objeto Recordset.

A sintaxe para o método Save é:

recordset.Save Destination, PersistFormat

Destination - Um variant que representa o caminho completo do arquivo onde o Recordset será salvo , pode ser também uma referência um objeto Stream
PersistFormat - Um valor PersistFormatEnum que define o formato no qual o Recordset será salvo , os formatos possíveis são: 
XML - adPersistXML         HTML  - adPersistHTML    e   o   padrão   adPersistADTG

Ex:    rsagenda.Save "c:\teste\agenda.dat" , adPersistADTG

Lembre-se que:

O método Save somente pode ser invocado em um Recordset aberto . Antes de usá-lo você deve usar o método Open para restaurar o recordset a partir do destino.

Se a propriedade Filter estiver ativa no Recordset , então , somente as linhas acessíveis no filtro serão salvas.

Ao salvar as alterações no recordset ele permanece aberto e você pode salvar as mudanças mais recentes.

Para alcançar um bom desempenho usando Save utilize a propriedade CursorLocation como adUseClient.

Vamos agora ao código das funções utilizadas no aplicativo agenda:

Na seção General Declarations do formulários insira o código abaixo , onde definimos as variáveis visíveis em todo o formulário.

Public rsagenda as ADODB.Recordset

Public strArquivo as String

Public Flag as Boolean

 

A seguir teremos o código que inicializa o nosso objeto recordset - rsagenda.  O código estará no evento Load do Formulário. Vejamos:

 

Private Sub Form_Load()

Dim icontador As Integer
Dim newitem As ListItem

Set rsagenda = New ADODB.Recordset

Call Abre_Recordset_Desconectado
Call Preenche_Lista


If rsagenda.RecordCount > 1 Then
   rsagenda.Filter = "Nome='" & ListAgenda.SelectedItem.Text & "'"
   Call Preenche_Controles
End If

End Sub

 

A procedura Abre_Recordset_Desconectado , verifica se o arquivo agenda.dat ( voce pode usar qualquer nome).Se o arquivo não existir ele será criado através da rotina Cria_Recordset_Desconectado:

 

Private Sub Abre_Recordset_Desconectado()
 
strArquivo = "c:\teste\agenda.dat"

If Dir(strArquivo) = "" Then
    Cria_Recordset_Desconectado
End If

rsagenda.Open strArquivo

End Sub

 

A rotina Cria_Recordset_Desconectado abaixo irá criar o recordset rsagenda com a estrutura já definida:

 

Private Sub Cria_Recordset_Desconectado()

With rsagenda

  Set .ActiveConnection = Nothing
   .CursorLocation = adUseClient
   .LockType = adLockBatchOptimistic

        With .Fields
           .Append "Nome", adVarChar, 50
           .Append "Endereco", adVarChar, 50
           .Append "Cidade", adVarChar, 40
           .Append "Cep", adVarChar, 15
           .Append "UF", adVarChar, 2
           .Append "telefone", adVarChar, 15
           .Append "email", adVarChar, 250
       End With
      .Open
      .Save strArquivo, adPersistADTG
      .Close


   End With

End Sub

 

A seguir a rotina Preenche_Lista irá preencher o controle ListView com os dados do recordset exibindo somente o nome constante no recordset. Abaixo o código:

 

Private Sub Preenche_Lista()

  With ListAgenda
     .View = lvwList
       Do Until rsagenda.EOF
          Set newitem = .ListItems.Add(, , rsagenda("Nome"))
          rsagenda.MoveNext
       Loop

       .SortKey = 0

   End With

    Set ListAgenda.SelectedItem = newitem

End Sub

 

A seguir usamos a propriedade Filter do recordset para filtrar o recordset , Assim :

 

   rsagenda.Filter = "Nome='" & ListAgenda.SelectedItem.Text & "'"

Perceba que o filtramos pelo campo Nome igual ao item atualmente selecionado na Lista.

 

Depois preenchemos os controles através da procedura Preenche_Controles abaixo:

 

Private Sub Preenche_Controles()

If rsagenda.RecordCount > 0 Then
        For icontador = 0 To rsagenda.Fields.Count - 1
             Set Text1(icontador).DataSource = rsagenda
             Text1(icontador).Text = rsagenda.Fields(icontador)
       Next
End If

End Sub

 

Para incluir dados no recordset basta clicar no botão - Incluir (cmdIncluir). O código é o seguinte:

 

Private Sub cmdincluir_Click(Index As Integer)
Dim icontador As Integer

ListAgenda.Sorted = False
Set ListAgenda.SelectedItem = Nothing

cmdsalvar.Enabled = True

For icontador = 0 To rsagenda.Fields.Count - 1
         Text1(icontador).Text = ""
Next
Text1(0).SetFocus

End Sub

 

A exclusão de um registro é obtida ao clicarmos no botão - Excluir (cmdexcluir) - cujo código é:

 

Private Sub cmdexcluir_Click(Index As Integer)

rsagenda.Delete adAffectCurrent

With ListAgenda
     .ListItems.Remove .SelectedItem.Index
     .SelectedItem = .ListItems(1)
     rsagenda.Filter = "Nome='" & .SelectedItem.Text & "'"
End With

Call Preenche_Controles

End Sub

 

A rotina mais importante é que salva o recordset em um arquivo definido . Usamos o arquivo agenda.dat . O botão cmsalvar ao ser clicado dispara o seguinte código:

 

Private Sub cmdsalvar_Click()

rsagenda.AddNew

For icontador = 0 To rsagenda.Fields.Count - 1
         rsagenda.Fields(icontador) = Text1(icontador).Text
Next

Call Salvar_Recordset_Desconectado
Call Preenche_Lista

cmdsalvar.Enabled = False

End Sub

 

Abaixo a procedure ListAgenda_ItemClick que atualiza os controles quando clicamos em um item da lista.

 

Private Sub ListAgenda_ItemClick(ByVal Item As MSComctlLib.ListItem)
   rsagenda.Filter = "Nome='" & ListAgenda.SelectedItem.Text & "'"
   Preenche_Controles
End Sub

 

Finalmente o código do evento Query_Unload que salva o recordset quando o usuário sai do aplicativo :

 

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
   rsagenda.Save strArquivo, adPersistADTG
End Sub

Abaixo a tela do aplicativo em funcionamento:

 

Viu como tratamos um recordset sem precisar de uma conexão com um banco de dados. A vantagem é que podemos usar quase todos os métodos e propriedades do objeto recordset ( addnew, delete , Filter , Sort , etc.. ) 

Eu não usei um tratamento de erros no exemplo , nem me preocupei com alguns possíveis erros ,  meu objetivo foi mostrar como trabalhar um recordset desconectado.

Acreditou agora !!!!


Copyright (c) 2001 - José Carlos Macoratti