Professional Documents
Culture Documents
Access 2000 allows you to generate persistent recordsets that can be stored on a local drive.
This article highlights the use of the these local recordsets to allow caching of the information
that is added to the Combo Box or List Boxes on Access Forms.
An example of why this is important is a combo box that uses zip (postal) codes for its data feed.
If 25 local machines query the network database to get these zip codes every time they open a
form with a zip code combo box, data traffic would slow down the server unnecessarily. Using
persistent recordsets, this can be handled locally and the updates can be resynchronized every
week or on demand.
By utilizing ActiveX Data Objects (ADO) and Smart Combo and List Boxes, you are now able to
take a load off your server by storing this information in a local cache on each of the PC's. This
article explains how you can use persistent recordsets in ADO for the caching. Once those
concepts are explained, I discuss how you can use a relatively hidden feature of Combo and List
Boxes that allows you to build your own record sources using visual basic. The information that
is discussed is relevant to Access 97 as well as Access 2000 and because Office is now a far
more integrated development tool, the concepts could very easily apply to other parts of Office or
the Visual Basic Environment. The article also introduce the idea of using a feature of ADO
version 2.2 to generate and using XML as an alternative method of handling cached recordsets.
An Access 2000 database called cache.mdb has been provided with the following objects
A text file called zipcodes.xml will show you what an XML file actually looks like.
Figure 1 - The form that handles all the caching options in this article. The numbered points on the
Left Hand Side of figure 1 will be used for reference throughout the article.
If you are going to try using ADO in Office 97, you will need to establish a reference in your Access
/Office project to the ADO Library plus ensure that the ADO library is installed on all the PC's that
you will be running the software on. The article downloads include a copy of the software that was
converted from Access 2000 back to Access 97 using the Access 2000 back conversion tool The
Access 97 software was not tested but you should be able to re-use the source code with a small
bit of persuasion.
If you wish to use ADO in Access 97 or XML in Office 2000, then download the ADO upgrade
(called MDAC) from
http://www.microsoft.com/data
Caching with ADO is handled using a method that allows you to save the current recordset to a
local file. Before you can use this method, you first need to define a recordset and connect to a
data source as follows. The simplest method for defining this connection in Access 2000 is using
the CurrentProject object.
Now the actual task to save the recordset to disk is the recordset save method
When the file is saved to disk, there is only one format available using the standard version of
Access 2000. This is a proprietary format called Advanced Data TableGram (ADTG). This is a
binary format and is only decipherable using the open recordset options described in section 2
below.
If you install version 2.2 of ADO on your PC, you will be able to use the open Extensible Markup
Language (XML) format. This approach is useful as it is a very easy way to turn recordsets into
this very important interchange format. Whether it actually benefits the caching process is
debatable as files are 50% bigger and they require the users of your software to install the 6
megabyte ADO upgrade on their computer. In the sample database, there is a toggle button to
switch between saving the file as XML or ADTG format. The save method for XML is as follows.
A sample of XML is shown as follows (Editor This Is an optional part of the article)
<xml xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882'
xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882'
xmlns:rs='urn:schemas-microsoft-com:rowset'
xmlns:z='#RowsetSchema'>
<s:Schema id='RowsetSchema'>
<s:ElementType name='row' content='eltOnly'>
<s:attribute type='ZipCode'/>
<s:attribute type='Suburb'/>
<s:extends type='rs:rowbase'/>
</s:ElementType>
<s:AttributeType name='ZipCode' rs:number='1' rs:nullable='true'
rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='string' dt:maxLength='8'/>
</s:AttributeType>
<s:AttributeType name='Suburb' rs:number='2' rs:nullable='true' rs:maydefer='true'
rs:writeunknown='true'>
<s:datatype dt:type='string' dt:maxLength='255'/>
</s:AttributeType>
</s:Schema>
<rs:data>
<z:row ZipCode='0852' Suburb='LAJAMANU'/>
<z:row ZipCode='0872' Suburb='KALTUKATJARA'/>
<z:row ZipCode='0886' Suburb='JABIRU'/>
<z:row ZipCode='2000' Suburb='ST JAMES'/>
</rs:data>
</xml>
To manage the external data files, you will need to handle the caching directory and the filenames
through constants or variables (so that you only store their definition once). The sample database
uses global constants as follows
Now we will retrieve the cached recordset and add it as a rowsource to the combo box. This is
achieved by looping through the recordset and building a value string that we add to the combo
box at the end of the recordset. For this example I have also added Row Headings to the output
string.
Do Until rst.EOF
strRowSrc = strRowSrc & rst(0) & ";" & rst(1) & ";"
rst.MoveNext
Loop
Me.cboManual.RowSource = strRowSrc
rst.Close
To make this example more universal, I refer to the names of the recordset columns and names
using the column number as follows recordset(ColumnNumber).name. Note also the use of a
semi colon to separate the data columns in the row source.
To make the combo boxes work in this example, I set the following properties
So this brings me to smart combo and list boxes. When I first ran into the 2048 character
restriction when programming my data mining shareware, the Access error message pointed out
that you could actually build your own function for passing data to the combo box. To find this
elusive help, ask the answer wizard to display information on "Value List" and choose "Create A
List Box that retrieves its rows from a function". You will need this help to expand on issues in this
article.
So how do these smart combo box functions work. Although the documentation is a little scant,
what you are doing is setting up a function that is called many different times to retrieve all the
information required by the combo box. You do not actually have to know how it does this but you
need to respond with the correct information for each of the different calls made to the function.
The arguments for the function are as follows
The Code argument informs the function what the combo box Access requires in the current
iteration and Col and Row which tells you what data to pass back for the column and row that the
Combo Box wishes to display.
To make this function the data source for your Combo Box, change the familiar Row Source Type
property from Table/Query or Value List or Field List and add the function that I have written
called "ZipCodes_FX" When the Access form first opens, the combo box will call that function and
start up the initialization sequence using the Code argument as follows
In this initialization sequence, the function reads the cached recordset and stores the information
into an array. As it is essential that the values in the array remain in place each time the function is
called, the array is dimensioned as Static.
tablesArray(Entries, 1) = rst(0).Name
tablesArray(Entries, 2) = rst(1).Name
Entries = 1
Do Until rst.EOF
tablesArray(Entries, 1) = rst(0)
tablesArray(Entries, 2) = rst(1)
rst.MoveNext
Entries = Entries + 1
Loop
rst.Close
ReturnVal = Entries
Now the combo box uses the Code argument to ask the function to return other useful information
such as the number of rows and columns in the data array.
Case acLBOpen
' Generate unique ID for control.
ReturnVal = timer
Case acLBGetRowCount
' Get number of rows.
ReturnVal = Entries
Case acLBGetColumnCount
' Get number of columns.
ReturnVal = 2
Case acLBGetColumnWidth
' Column width -1 forces use of default width
' You can override this property on the combo
ReturnVal = -1
But the most important step is when Access asks the function to return the information from the
array. When the combo box has all its values, the function is called one last time where it is good
coding practice to clear the Static Array from memory using the Erase statement
Case acLBGetValue
' Returns the data one array row at a time
ReturnVal = tablesArray(row, 1 + col)
Case acLBEnd
' On completion, clear the static array
Erase tablesArray
End Select
ZipCodes_FX = ReturnVal
You can also set up smart list boxes to add the cached file to the row source of a List Box by
utilizing the same function. The property that handles this is set as follows
The code that I use to rebuild the cache is exactly the same as illustrated in section 1) of this
article. When the cache recordset is rebuilt, the module return to the next line in the smart combo
box code by using a good old fashioned goto statement.
Whilst I was building the software for this article, I came up with many different ideas for deciding
whether a recordset needed to be refreshed. Finally I decided that every system probably will be
different so I made up this simple rule
"If the cached file does not exist, then the smart combo box function should refresh the recordset. "
This way refreshing your cached recordsets could be something as simple as sending an email to
your end users to hit the Clear Cache button in the utilities section of your software. This is the
command button code that would clear the files that are being used in this system
To make this more universal, you would need to store your filenames in tables and your cache
directory as optional location on the users PC.
References
http://msdn.microsoft.com/library/periodic/period99/html/SA99E1.HTM
http://msdn.microsoft.com/library/periodic/period98/html/df0798.htm
Conclusion
If you are using Microsoft Access and sharing its data amongst a number of end users, you will be
passing all the information required by your forms from the server to the client every time you
using a combo or list box on a form. Whilst this will generally be quite trivial when you are
displaying a few rows from a lookup table, sometimes you may require more than a 1000 rows of
data. If you are then to multiply this traffic by a large number of PC's, the amount of data traffic
can add up. By using some the techniques in this article, you can start to take a load of the server
and start using those ultra fast local drives that PC's come with these days.
More importantly though are the different techniques that you now can use to enhance your
applications. Firstly is processing of persisted recordsets locally in any type of application can
make your application more efficient. The second lesson is how easy it is to use ADO to
automatically generate XML files for your intranet/internet applications. And finally are the smart
combo and list boxes which can be used to add some special functionallity to your application.
Garry Robinson
Editor of vb123.com