Accessing ADO
Peter Vogel
ActiveX Data Objects is the
successor to Data Access Objects, and with Access 2000, ADO finally goes
mainstream. Here's a quick look at some neat things that Access 2000 and
ADO can do together.
What really brought home to me that ADO was the future of data access came
when I loaded up Access 2000. After I started Access 2000, I added a Basic
module and went to the References list to see what was listed. Jet 4.0,
the new version of DAO, wasn't even listed. The current version of Jet (3.5)
was listed, but it wasn't checked off. What was both listed and invoked
was ADO. For at least the first beta of Access, if you start writing code
to get at your database, you're going to start using ADO.
You might as well hear it from me: ADO is different. If you don't write
code, this isn't going to be an issue for you -- you can go right on using
QueryDefs and setting Form properties. However, if you do write code, you're
going to have to learn a new way of doing things. The good news is that
ADO lets you use Access in ways that just weren't possible with DAO. In
this article, I want to show you some of the ways that ADO integrates with
Access.
The ADO objects
There are three major objects in the ADO
environment: connection, command, and recordset. Unlike the DAO recordset,
the ADO recordset can be created from scratch without accessing any prior
objects. Here, for instance, is some sample code that creates a recordset:
Dim rec As Recordset
Set rec = New Recordset
rec.Source = "Select * From Table1;"
rec.ActiveConnection = "DSN=MyDSN;"
rec.Open
|
The second line of code really brings home the difference between ADO and
DAO: A recordset is created using the New command rather than through the
CreateRecordset method of some other DAO object. I think of these as "empty"
recordsets because they contain no records or, indeed, any association with
a datasource from which records could be retrieved. In DAO, when a recordset
is created, it draws information from the object from which it's created
(either a Database or a QueryDef object) and thus "knows" which
database it's to draw its records from.
Since this recordset doesn't have any place from which to get this information,
it must have it passed to it through its properties. The Source property
allows you to specify the command or parameters that are used to specify
the data to be retrieved. In this case, that's a SQL statement.
The ActiveConnection property allows you to specify where the data for the
recordset is to come from. Like an ODBC connect string, this can be quite
a long list of parameters, including the name of the database, the userid
and password to log on with, and much more. I've ducked the issue in this
example by creating a DataSourceName using the ODBC manager and setting
the ActiveConnection property to the name of the DSN. One of the nice things
about converting to ADO is that you can continue to work with your existing
ODBC databases.
The recordset's Open method uses the information specified in the properties
to retrieve the specified records into the recordset. From there on, you
can use the DAO methods that you're used to: MoveFirst, MoveNext, and MoveLast.
There's at least one thing to be aware of, though: The RecordCount property
in ADO almost always reflects the number of records to be retrieved into
the recordset (unlike DAO, where the RecordCount property reflected only
the records already read).
Access and ADO
The contents of a typical Connection property
look like this:
Provider=Microsoft.Jet.OLEDB.4.0;Persist Security
Info=False;User ID=Admin;Data Source=D:\Program
Files\Microsoft Office\Office\1033\Mydb.mdb;Mode=Share
Deny None;Extended Properties="";Locale
Identifier=1033;Jet OLEDB:System database=D:\Program
Files\Microsoft Office\Office\system.mdw;Jet
OLEDB:Registry Path="";Jet OLEDB:Database Password="";Jet
OLEDB:Engine Type=5;Jet OLEDB:Database Locking Mode=0;Jet
OLEDB:Global Partial Bulk Ops=2;Jet OLEDB:Global Bulk
Transactions=1;Jet OLEDB:New Database Password="";Jet
OLEDB:Create System Database=False
|
You don't want to type it in if you can avoid it. Access makes using ADO
to get at Jet a little bit easier by providing a Connection property from
the CurrentProject object. This property provides the complete ADO connection
string for a Jet database. To work with the Jet database that the code is
executing in, I need only change the line that sets the ActiveConnection
property to this:
rec.ActiveConnection = CurrentProject.Connection
|
There has always been a disconnect between Access's Rapid Application Design
features and its support for coding. I can knock together a form that displays
and manages data in little or no time. However, if I want retrieve my data
into a recordset using VBA code and then display that data in a form, things
get a little tougher. At the very least, I'd have to move the data field
by field from the recordset to the text boxes on the form:
Me!Text1 = rec("Field1")
Me!Text2 = rec("Field2")
etc.
|
This is a painful process and expensive when it comes to maintaining the
application. If one field is added or removed from the recordset, I'd have
to track down the code that shuffled the data between the recordset and
the form and add (or remove) the offending field.
With Access 2000, that disconnect disappears. Access 2000 forms have a new
Recordset property that can be set to a recordset generated in code:
When designing your form, you can bind your controls to any field by setting
the field's ControlSource property as usual. You don't need to set the form's
RecordSource property at all -- the Recordset will be set at runtime when
you pass a recordset object to the form's Recordset property.
There are some restrictions on this magic: The recordset must be a Keyset
recordset, which corresponds most closely to the Jet dynaset. You control
the recordset type by setting the CursorType property to one of a set of
predefined constants. Here's some code that creates a recordset object of
the appropriate type and then passes it to a form to display:
Dim rec As Recordset
Set rec = New Recordset
rec.Source = "Select * From Table1;"
rec.ActiveConnection = CurrentProject.Connection
rec.CursorType = adOpenKeyset
rec.Open
Set Me.Recordset = rec
|
ADO recordsets
As long as I've brought in the CursorType
property, I should mention that the ADO recordset doesn't have quite the
same distinctions between Recordset/Snapshot/Table that DAO had. In DAO,
you could retrieve either the keys for a set of records when you created
the recordset (a Dynaset) or all of the field for a set of records (a Snapshot).
In some situations, a Snapshot recordset was more efficient than a Dynaset
because no further trips to the database were required to retrieve the actual
data. With a Dynaset, as you did a MoveFirst to each record, DAO used the
key it had retrieved to get the record's data. More importantly, a Snapshot
was essential when you wanted to ensure that all the records you processed
reflected the state of the database at a specific point in time (hence,
the name Snapshot). However, Snapshot was also a read-only set of records.
In ADO, those two attributes are separated. You can create a read-only Dynaset
or an updateable Snapshot. The CursorType property allows you to specify
whether all of the data is to be retrieved or just the keys (setting the
CursorType to adOpenStatic will retrieve all the data for the records).
The LockType property allows you to specify, independent of the recordset
type, whether the recordset is updateable (setting LockType to adLockReadOnly
makes the recordset read-only). Again, here's a difference between DAO and
ADO: The default setting for the LockType property is read-only.
When you move to ADO, you really have to become aware of how objects work,
and the recordset object demonstrates this need. Take a quick look at this
code and tell me whether you think the form will still be displaying the
records from table1 when the routine finishes:
Set Me.Recordset = rec
Set rec = Nothing
|
The answer is yes. In the code earlier in this article, I used the New statement
to create a recordset object and point the rec variable at that object.
But the rec object variable isn't the object; rec is merely the object
variable that points to the object. In the preceding code, the form's Recordset
property is also aimed at the recordset object. When the rec object variable
is set to Nothing in the last line in the preceding code, all that happens
is that one less item is using the object. But as long as one pointer to
the recordset object remains, in this case the form's Recordset property,
the recordset object will continue to exist. Which means, among other things,
that the rec object variable in the preceding code could easily be reused
to create another ADO recordset without affecting the recordset that the
form is based on.
It's coming
This has been a quick intro to using ADO
with Access 2000. I've only looked at a small part of one of the ADO objects,
but you can see what's coming. ADO lets you do things that you couldn't
before, and Access 2000 integrates with ADO in some very exciting ways.
A lot of what you know (MoveFirst, MoveLast) will continue to work for you,
and some things that you know (Recordcount) will change in interesting ways.
You can start using ADO right now in any Windows 95 development tool, but
using ADO and Access 2000 together gives a tremendous tool for creating
database applications.
Peter Vogel, MCSD, is the editor
of Smart Access and a principal in PH&V Information Services (a technology
management company). In addition, he teaches for Learning Tree International
and wrote their Internet applications development course. Sybex recently
published the MCSD: Access 95 Certification guide, which he co-wrote with
Helen Feddema. peter.vogel@phvis.com.