Directory listing of http: uap.unnes.ac.id ebook biblebook Visual Basic 6 com & Library Books

15
C H A P T E R

Working with
Recordsets —
Part I I









In This Cha pter
Accessing fields
in a reco rdset

I


n this c hapter, I’ll c o ntinue my disc ussio n o f the ADO
Recordset o bjec t by c o vering ho w to ac c ess the info rmatio n c o ntained in the vario us fields. Then I’ll explain ho w to
mo ve aro und and lo c ate rec o rds in the Recordset.

M ore About Recordsets
As yo u kno w, a Recordset o bjec t c o ntains a c o llec tio n o f
ro ws returned fro m the database. Rather than make all o f the
ro ws available to yo u at o ne time, it maintains a po inter to the
c urrent ro w that yo u c an mo ve thro ugh the rec o rdset using
vario us metho ds and pro perties. The info rmatio n c o ntained
in the ro w’s c o lumns is made available thro ugh the Fields
c o llec tio n. Depending o n yo ur c urso r type, yo u c an c hange
the values lo c ally and then c o mmit the values to the database
using the appro priate metho ds.

The Field Object
The Field o bjec t c o ntains info rmatio n abo ut a spec ific c o lumn in a Recordset. It is part o f the Fields c o llec tio n, whic h
c o ntains the set o f c o lumns retrieved fro m the database.

Mo ving aro und in

a reco rdset
So rting and
filtering ro ws
Co llecting reco rdset
info rmatio n
G etting info rmatio n
fro m fields
W o rking with
larg e values









300


Part III ✦ Hardcore ADO

Field object properties
Table 15-1 lists the pro perties asso c iated with the Field o bjec t. Tables 15-2 and
15-3 c o ntain additio nal info rmatio n abo ut spec ific pro perties listed in Table 15-1.
Note

Values, values and more values: Each field has three properties that describe its
value. Value contains the current value of the field. OriginalValue contains
the value as it w as originally retrieved from the database. UnderlyingValue
contains the current value for the field, w hich m ay reflect changes m ade by other
transactions.

Table 15-1
Properties of the Field Object
Property

Description

ActualSize


A Long value containing the actual length of a field’s value.

Attributes

An enum erated type describing the characteristics of the colum n
(see Table 15-2).

DataFormat

An object reference to a StdDataFormat object containing
inform ation about how to form at the data value.

DefinedSize

A Long containing the m axim um length of a field’s value.

Name

A String value containing the nam e of the field.


NumericScale

A Byte value containing the num ber of digits to the right of the
decim al point for a num eric field.

OriginalValue

A Variant containing the original value of the field before any
m odifications w ere m ade.

Precision

A Byte value containing the total num ber of digits in a num eric
field.

Properties

An object reference to a Properties collection containing
provider-specific inform ation about a field.


Type

An enum erated type containing the OLE DB data type of the field
(see Table 15-3).

UnderlyingValue

A Variant containing the current value of the field in the
database as it exists on the database server.

Value

A Variant containing the current value of the field.

Chapter 15 ✦ Working with Recordsets —Part II

Table 15-2
Values for Attributes
Constant


Value

Description

adFldUnspecified

-1

The provider doesn’t supply field attributes.

adFldMayDefer

2

The field value is not retrieved w ith the w hole
record, but only w hen you explicitly access the
field.

adFldUpdateable


4

The field’s value m ay be changed.

adFldUnknownUpdateable

8

The provider can’t determ ine if you can change
the field’s value.

adFldFixed

16

The field contains fixed-length data.

adFldIsNullable


32

The field w ill accept Null values.

adFldMayBeNull

64

The field m ay contain a Null value.

adFldLong

128

The field contains a long binary value and you
should use the AppendChunk and GetChunk
m ethods to access its data.

adFldRowID


256

The field contains an identity value w hich can’t
be changed.

adFldRowVersion

512

The field contains a tim e stam p value that is
used to track updates.

adFldCacheDeferred

4096

This field is cached by the provider and
subsequent reads and w rites are done from
cache.


adFldIsChapter

8192

The field contains a chapter value, w hich
specifies a specific child Recordset related to
this parent field.

adFldNegativeScale

16384

The field contains a num eric colum n that
supports negative scale values.

adFldKeyColumn

32768

The field is (or at least part of) the prim ary key
for the table.

adFldIsRowURL

65536

The field contains the URL that nam es the
resource from the data store represented by
the record.
Continued

301

302

Part III ✦ Hardcore ADO

Table 15-2 (continued)
Constant

Value

Description

adFldIsDefaultStream

131072

The field contains the default stream for the
resource represented by the record.

adFldIsCollection

262144

The field contains a collection of another
resource such as a folder rather than a sim ple
resource such as a file.

Table 15-3
Values for Type
Constant

Value

adEmpty

0

Description
This field has no value (OLE DB data type value:

DBTYPE_EMPTY).
adSmallInt

2

adInteger

3

This field has an Integer value (OLE DB data type
value: DBTYPE_I2).
This field has a Long value (OLE DB data type value:

DBTYPE_I4).
adSingle

4

This field has a Single value (OLE DB data type
value: DBTYPE_R4).

adDouble

5

This field has a Double value (OLE DB data type
value: DBTYPE_R8).

adCurrency

6

This field has a Currency value (OLE DB data type
value: DBTYPE_CY).

adDate

7

This field has a Date value (OLE DB data type value:
DBTYPE_DATE).

adBSTR

8

This field has a null-term inated Unicode string (OLE
DB data type value: DBTYPE_BSTR).

adIDispatch

9

This field has a pointer to an IDispatch interface in
a COM object (OLE DB data type value:
DBTYPE_IDISPATCH).

adError

10

This field has a 32-bit error code (OLE DB data type
value: DBTYPE_ERROR).

adBoolean

11

This field has a Boolean value (OLE DB data type
value: DBTYPE_BOOL).

Chapter 15 ✦ Working with Recordsets —Part II

Constant

Value

Description

adVariant

12

This field has a Variant value (OLE DB data type
value: DBTYPE_VARIANT). Note that w hile this type
is supported by OLE DB, but it is not supported by
ADO. Using it m ay cause unpredictable results.

adIUnknown

13

This field has a pointer to an IUnknown interface in a
COM object (OLE DB data type value:
DBTYPE_IUNKNOWN).

adDecimal

14

This field has an exact num eric value w ith a fixed
precision and scale (OLE DB data type value:
DBTYPE_DECIMAL).

adTinyInt

16

This field has a one byte signed integer (OLE DB data
type value: DBTYPE_I1).

adUnsignedTinyInt

17

This field has a one byte unsigned integer (OLE DB
data type value: DBTYPE_UI1).

adUnsignedInt

18

This field has a tw o byte unsigned integer (OLE DB
data type value: DBTYPE_UI2).

adUnsignedInt

19

This field has a four byte unsigned integer (OLE DB
data type value: DBTYPE_UI4).

adBigInt

20

This field has an 8-byte signed integer (OLE DB data
type value: DBTYPE_I8).

adUnsignedBigInt

21

This field has an 8-byte unsigned integer (OLE DB
data type value: DBTYPE_UI8).

adFileTime

64

This field has a 64-bit date-tim e value represented as
the num ber of 100-nanosecond intervals since 1
January 1601 (OLE DB data type value: DBTYPE_
FILETIME).

adGUID

72

This field has a globally unique identifier value (OLE
DB data type value: DBTYPE_GUID).

adBinary

128

This field has a Binary value (OLE DB data type
value: DBTYPE_BYTES).

adChar

129

This field has a String value (OLE DB data type
value: DBTYPE_STR).

adWChar

130

This field contains a null-term inated Unicode
character string (OLE DB data type value: DBTYPE_
WSTR).

adNumeric

131

This field contains an exact num eric value w ith a fixed
precision and scale (OLE DB data type value:
DBTYPE_NUMERIC).
Continued

303

304

Part III ✦ Hardcore ADO

Table 15-3 (continued)
Constant

Value

Description

adUserDefined

132

This field contains a user-defined value ( DBTYPE_UDT).

adDBDate

133

This field has a date value using the YYYYMMDD
form at (OLE DB data type value: DBTYPE_DBDATE).

adDBTime

134

This field has a tim e value using the HHMMSS form at
(OLE DB data type value: DBTYPE_DBTIME).

adDBTimeStamp

135

This field has a date-tim e stam p in the YYYYMMDDHH
MMSS form at (OLE DB data type value: DBTYPE_
DBTIMESTAMP).

adChapter

136

This field has a 4-byte chapter value that identifies the
row s in a child row set (OLE DB data type value:
DBTYPE_HCHAPTER).

adPropVariant

138

This field has an Autom ation PROPVARIANT (OLE DB
data type value: DBTYPE_PROP_VARIANT).

adVarNumeric

139

This field contains a num eric value. (Available for

Parameter objects only.)
adVarChar

200

adLongVarChar

201

This field contains a String. (Available for
Parameter objects only.)
This field has a long character value. (Available for

Parameter objects only.)
adVarWChar

202

This field has a null-term inated Unicode character
string value. (Available for Parameter objects only.)

adLongVarWChar

203

This field has a long null-term inated character string
value. (Available for Parameter objects only.)

adVarBinary

204

This field has a binary value. (Available for
Parameter objects only.)

adLongVarBinary

205

This field has a long binary value. (Available for

Parameter objects only.)

Field object methods
The Field o bjec t c o ntains two metho ds that help yo u deal with large fields.

Chapter 15 ✦ Working with Recordsets —Part II

Sub AppendChunk (Data as Variant)
The AppendChunk metho d is used to add data to a large text o r binary field. The
first time the AppendChunk metho d is used, the value in Data will o verwrite any
existing data in the field. Fo r subsequent c alls, simply append data to the end o f
the existing data.

Data is a Variant c o ntaining the data to be appended to the end o f the field.

Function GetChunk (Length as Long) as Variant
The GetChunk metho d is used to retrieve data fro m a large text o r binary field. The
first time GetChunk is c alled, the data will be retrieved fro m the start o f the field. Only
the number o f bytes (o r Unic o de c harac ters) spec ified will be retrieved. Subsequent
c alls will retrieve data fro m where the previo us c all left o ff. If yo u spec ify a length
greater than the remaining data, o nly the remaining data will be returned witho ut
padding.
Note

A long, long chunk ago: You can only use the GetChunk and the AppendChunk
m ethods w hen the adFldLong bit is set in the Attributes property.

Length is a Long c o ntaining the number o f bytes o r c harac ters o f data to be
retrieved.

The Fields Collection
The Fields c o llec tio n c o ntains the set o f c o lumns being returned in a Recordset
o bjec t.

Fields collection properties
Table 15-4 lists the pro perties asso c iated with the Fields c o llec tio n.

Table 15-4
Properties of the Fields Collection
Property

Description

Count

A Long value containing the num ber of Field objects in the collection.

Item( index)

An object reference to a Field object containing inform ation about a
particular field in the Recordset. To locate a field, specify a value in
the range of 0 to Count –1 or the nam e of the Field.

305

306

Part III ✦ Hardcore ADO

Note

Special fields: The tw o special fields that are defined for a Record object are the
default Stream object (index = adDefaultStream) and the absolute URL for
the Record (index = adRecordURL).

Fields collection methods
The Fields c o llec tio n c o ntains metho ds that are used to maintain the set o f Field
o bjec ts.

Sub Append (Name As String, Type As DataTypeEnum, [DefinedSize As
Long], [Attrib As FieldAttributeEnum = adFldUnspecified], [FieldValue
As Variant])
The Append metho d c reates a new Field o bjec t and adds it to the Fields c o llec tio n.

Name is a String value c o ntaining the name o f the field.
Type is the data type that will be asso c iated with the new field.
DefinedSize is a Long c o ntaining the size o f the new field.
Attrib is a bit pattern c o ntaining values that determine the c harac teristic s o f the
field (see Table 15-2 fo r the po ssible values fo r this pro perty).
FieldValue is a Variant that c o ntains the value fo r the new field. If this value isn’t
spec ified, then the field will be Null .

Sub Delete (Index As Variant)
The Delete metho d remo ves a Field fro m the c o llec tio n. Index is either a String
c o ntaining the name o f the field o r a Long value c o ntaining the o rdinal po sitio n o f
the Field o bjec t to be deleted.

Sub Refresh( )
The Refresh metho d has no real effec t o n the Fields c o llec tio n. To see a c hange
in the underlying database struc tures, yo u need to issue a Requery metho d o f the
Recordset o bjec t.

Sub Update( )
The Update metho d is used to save the c hanges yo u make to the Fields c o llec tio n.

Chapter 15 ✦ Working with Recordsets —Part II

M oving Around a Recordset
Yo u c an use the Recordset o bjec t to gain ac c ess to the set o f ro ws selec ted fro m
the database. Yo u c an o nly ac c ess o ne ro w at a time with the curre nt re co rd po inte r,
whic h allo ws yo u to use vario us metho ds and pro perties to c hange the rec o rd that
the c urrent rec o rd po inter is po inting to .

The Recordset M ovement Demo program
To demo nstrate the different ways to mo ve aro und in a Recordset, I wro te the
Rec o rdset Mo vement Demo pro gram (see Figure 15-1). This pro gram might no t win
the award fo r the Wo rld’s Mo st Cluttered windo w, but it wo uld c ertainly plac e in the
to p five. Ho wever, it do es ac c o mplish its go al o f presenting the maximum amo unt o f
info rmatio n abo ut what happens when yo u mo ve aro und in a Recordset.

Figure 15-1: Running the Recordset Movem ent Dem o program

On the
CD-ROM

This program can be found on the CD-ROM in the \VB6DB\Chapter15\
RecordsetMovementDemo directory.

307

308

Part III ✦ Hardcore ADO

Running the program
In o rder to try mo ving aro und in a rec o rdset with this pro gram, yo u must first c o nnec t to yo ur database. Enter yo ur user name and passwo rd info rmatio n in the appro priate blanks in the Co nnec tio n frame and press the Co nnec t butto n. Respo nd Yes to
the message bo x that asks “Do yo u really want to c o nnec t?”. If yo u were able to suc c essfully c o nnec t to the database server, the message “Co nnec ted” will be displayed
in the status bar at the bo tto m o f the fo rm.
Onc e yo u’re c o nnec ted to the database server, yo u c an o pen the Recordset in the
Open Rec o rdset frame. Yo u may enter a two -c harac ter state name in the field c alled
Selec t State to restric t the Recordset so that it o nly c o ntains c usto mers fro m the
spec ified state. Otherwise, the rec o rdset will c o ntain all o f the c usto mers fro m the
database.
Yo u c an also spec ify the number o f rec o rds yo u want per page in the Page Size field.
The default value is ten. Then yo u c an c ho o se values fo r Curso r Lo c atio n, Curso r
Type, and Lo c k Type pro perties. Pressing Open Rec o rdset will o pen the rec o rdset.
Yo u c an c hange any o f these values and press the Open Rec o rdset butto n to c lo se
the c urrent rec o rdset and o pen it again with the new parameters.
The c urrent status o f the Recordset o bjec t is rec o rded in the Rec o rdset Status
frame. The values fro m three fields are displayed, alo ng with the c urrent status o f the
BOF and EOF pro perties. No rmally the BOF o r EOF bo xes will be blac k, indic ating that
the c urrent rec o rd po inter isn’t po inting to either extreme. When yo u read either BOF
o r EOF, the appro priate bo x will be displayed in yello w. If yo u are already o n BOF o r
EOF and attempt to mo ve beyo nd the end o f the rec o rdset a sec o nd time, the bo x will
be displayed in red. Also displayed are the values fro m the AbsolutePosition,
RecordCount, AbsolutePage, PageCount, and Bookmark pro perties.
Onc e yo u have o pened the Recordset, yo u c an mo ve aro und using the c o ntro ls in
the Mo ve Demo , Filter, Find, and So rt frames o f the fo rm. No te that yo u c an’t update
any o f the fields in the database. I’ll disc uss updating info rmatio n in a rec o rdset in
Chapter 16.
Caution

Check before you click: I don’t check m ost of the input param eters before using
them , so don’t be surprised if the program gets a fatal error or does som ething
unpredictable if you enter the w rong value.

M odule level declarations
The Rec o rdset Mo vement Demo pro gram inc ludes a few variables dec lared at the
mo dule level, making them glo bal to the entire mo dule (see Listing 15-1). These
inc lude the Customers Recordset o bjec t, the db Connection o bjec t and the
SaveBookmark variable. No te that I dec lared bo th the Recordset and Connection
o bjec ts WithEvents, whic h allo w me to mo nito r the status o f bo th o bjec ts with the
appro priate events to trac k their status.

Chapter 15 ✦ Working with Recordsets —Part II

Listing 15-1: M odule level declarations for Recordset
M ovement Demo
Option Explicit
Dim WithEvents Customers As ADODB.Recordset
Dim WithEvents db As ADODB.Connection
Dim SaveBookmark As Variant

M oving sequentially
The c urrent rec o rd is a po inter to o ne o f the ro ws in the Recordset. Assume that
yo u retrieve a Recordset fro m yo ur database with seven ro ws. Befo re the first ro w
in the rec o rdset is a spec ial marker kno wn as the BOF, while the EOF marker is
beyo nd the end o f the last ro w. The c urrent rec o rd po inter c an po int to any o f
these lo c atio ns ( see Figure 15-2) .

Current Record Pointer

EOF

1

2

3

4

5

6

7

EOF

Figure 15-2: A logical view of the current record pointer

Note

Absolutely addressed: The record num bers show n in Figure 15-2 correspond to
the values of the AbsolutePosition property, except for BOF and EOF, w hich
don’t have a corresponding value for AbsolutePosition.

When yo u first o pen a Recordset, the c urrent rec o rd po inter is po inting to the first
rec o rd (assuming o f c o urse that there is at least o ne rec o rd in the rec o rdset). Fro m
this lo c atio n, yo u c an mo ve to the next rec o rd (rec o rd number 2) in sequenc e using
the MoveNext metho d. Using the MoveLast metho d will take yo u to rec o rd number 7,
whic h is the last rec o rd in the rec o rdset. Yo u c an return to the first rec o rd by using
the MoveFirst metho d, and yo u c an mo ve to the previo us rec o rd using the
MovePrevious metho d.

309

310

Part III ✦ Hardcore ADO

M oving beyond the ends
One pro blem with the MoveNext metho d is that if yo u are at the last rec o rd in the
rec o rdset, there is no thing to prevent yo u fro m trying to mo ve beyo nd the end.
When this happens, the c urrent rec o rd po inter is mo ved to EOF. While the c urrent
rec o rd po inter po ints to EOF, any attempt to ac c ess c o lumn info rmatio n results in
an erro r. The same pro blem o c c urs with the MovePrevious metho d and the beginning o f the Recordset.
The so lutio n to this pro blem is to no t leave the c urrent rec o rd po inter po inting to
EOF o r BOF. This c o nditio n c an be detec ted by using the EOF and BOF pro perties.
The EOF pro perty is TRUE o nly when the c urrent rec o rd po inter is po inting beyo nd
the last rec o rd, while the BOF pro perty is o nly TRUE if the c urrent rec o rd po inter is
po inting befo re the first rec o rd. No te that if bo th pro perties are TRUE, the Recordset
do esn’t c o ntain any rec o rds.

Using the M oveNext method
Using these metho ds is very straightfo rward. All yo u really need to do is to c all the
desired metho d; ho wever, this isn’t really prac tic al sinc e it do esn’t do any erro r
c hec king. A mo re prac tic al example is sho wn in Listing 15-2. This ro utine verifies
that the Recordset isn’t already at the end o f file marker befo re it c alls the
MoveNext metho d. This ensures that yo u c an’t mo ve beyo nd EOF.

Listing 15-2: The M oveNextDemo routine
Sub MoveNextDemo()
If Not Customers.EOF Then
Customers.MoveNext
End If
End Sub

An alternate M oveNext
Ano ther way to handle the MoveNext metho d is sho wn in Listing 15-3. This ro utine
uses the On Error Resume Next statement and the Err o bjec t to detec t when the
MoveNext fails. If it do es fail, then my o ld friend WriteError is used to display the
database message.

Chapter 15 ✦ Working with Recordsets —Part II

Listing 15-3: The Command5_Click event in Recordset
M ovement Demo
Private Sub Command5_Click()
On Error Resume Next
StatusBar1.SimpleText = “”
Err.Clear
Customers.MoveNext
If Err.Number 0 Then
WriteError
End If
End Sub

Ho wever, to make the Co mmand5_Clic k event wo rk pro perly, I also have to c o de the
WillMove event to detec t and c anc el any attempt to mo ve beyo nd the BOF o r EOF
(see Listing 15-4). This ro utine detec ts when yo u are at EOF o r BOF and are abo ut to
perfo rm a metho d that wo uld trigger an erro r, and sets the adStatus parameter to
adStatusCancel to return an erro r c o nditio n.

Listing 15-4: The Customers_WillM ove event in Recordset
M ovement Demo
Private Sub Customers_WillMove( _
ByVal adReason As ADODB.EventReasonEnum, _
adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset)
If Customers.BOF And adReason = adRsnMovePrevious Then
adStatus = adStatusCancel
End If
If Customers.EOF And adReason = adRsnMoveNext Then
adStatus = adStatusCancel
End If
End Sub

311

312

Part III ✦ Hardcore ADO

M oving randomly
There are several ways to mo ve aro und the Recordset rando mly. The o ne yo u
sho uld use depends o n what yo u are trying to ac c o mplish. The Bookmark pro perty
allo ws yo u to save the lo c atio n o f a ro w and be able to return to that ro w at so me
future po int in time. The Move metho d allo ws yo u to mo ve fo rward o r bac kward the
spec ified number o f ro ws. The AbsolutePage pro perty allo ws yo u to jump to the
spec ified page number in the Recordset. If yo ur rec o rdset suppo rts it, yo u c an
also use the AbsolutePosition pro perty to po sitio n the c urso r at a spec ific lo c atio n in the rec o rdset.

Using bookmarks
The Bookmark pro perty c o ntains the c urrent lo c atio n o f a rec o rd in a Recordset. It
is a Variant value that is highly dependent o n the data pro vider. It is po ssible to
have multiple bo o kmarks that po int to the same rec o rd, but eac h bo o kmark is a different value. The o nly way to c o mpare bo o kmarks is to use the CompareBookmarks
metho d. Also , a Bookmark is spec ific to the Recordset that it c ame fro m. Yo u c an’t
use it with any o ther rec o rdsets, even if they were c reated with the same c o mmand.
Note

Cloned again: A Bookmark can be used w ith any copy of a Recordset that w as
created using the Clone m ethod.

To save a bo o kmark, simply dec lare a Variant variable and save the value o f the
Bookmark pro perty to it, as sho wn belo w.

SaveBookmark = Customers.Bookmark
This saves the lo c atio n o f the c urrent rec o rd. Then after mo ving to a different
rec o rd, yo u c an mo ve the c urrent rec o rd po inter bac k to the bo o kmarked lo c atio n
by assigning the value yo u saved bac k to the Bookmark pro perty. When yo u add
so me erro r-handling lo gic , yo u end up with c o de like yo u see in Listing 15-5.

Listing 15-5: The Command8_Click of Recordset M ovement
Demo
Private Sub Command8_Click()
On Error Resume Next
StatusBar1.SimpleText = “”
Err.Clear
Customers.Bookmark = SaveBookmark

Chapter 15 ✦ Working with Recordsets —Part II

If Err.Number 0 Then
WriteError
End If
End Sub

M oving forward and backward
The Move metho d takes two parameters: the number o f ro ws to mo ve and an
o ptio nal Bookmark that will be used as the starting lo c atio n. The number o f ro ws
may be either po sitive o r negative. A po sitive value will mo ve the spec ified number
o f ro ws to ward the last ro w o f the Recordset, while a negative value will mo ve
to ward the first ro w. If yo u spec ify a value o f zero , the c urrent rec o rd will be
refreshed.
Spec ifying the bo o kmark c o mputes the o ffset relative to that rec o rd rather than the
c urrent rec o rd. Of c o urse, the Recordset must suppo rt bo o kmarks in o rder to use
this parameter.
Listing 15-6 sho ws ho w easy it is to c all the Move metho d. While yo u might think
that the erro r c hec king in this ro utine isn’t nec essary, think again. If yo u spec ify to o
large o f a value (fo r example, o ne that wo uld take yo u beyo nd the end o f the rec o rdset), a run-time erro r will be triggered.

Listing 15-6: The Command7_Click event of Recordset
M ovement Demo
Private Sub Command7_Click()
On Error Resume Next
StatusBar1.SimpleText = “”
Err.Clear
Customers.Move CLng(Text14.Text)
If Err.Number 0 Then
WriteError
End If
End Sub

313

314

Part III ✦ Hardcore ADO

Reading pages
One o f the mo re interesting features o f ADO is its ability to manage data in terms o f
pages. A page is a gro up o f rec o rds fro m the database. The PageSize pro perty
determines the number o f rec o rds in a page, while the PageCount pro perty tells
yo u the number o f pages in yo ur Recordset. The AbsolutePage pro perty c o ntains
the relative number o f the c urrent in the rec o rdset.
Yo u c an repo sitio n the c urrent rec o rd po inter by setting the AbsolutePage pro perty to a partic ular page, as sho wn belo w:

Customers.AbsolutePage = CLng(Text18.Text)
This will mo ve the c urrent rec o rd po inter to the first rec o rd o n that page. Yo u c an
even c hange the PageSize pro perty while the Recordset o bjec t is o pen, whic h
makes it easy to c hange the number o f rec o rds displayed per page o n the fly.
Tip

Internet ready: The page properties are often useful in an Internet or transactionoriented environm ent w here a user scrolls though a recordset one page at a tim e.
You can use the AbsolutePage property to determ ine w hich page needs to be
displayed, and then use the MoveNext m ethod to retrieve the rem aining row s on
the page.

Absolute positioning
If yo ur rec o rdset suppo rts the AbsolutePosition and RecordCount pro perties,
yo u c an determine the c urrent rec o rd numb er and the to tal rec o rds in yo ur
Recordset. The AbsolutePosition pro perty will also allo w yo u to mo ve the
c urso r to the spec ified lo c atio n.
Caution

Absolute ain’t accurate: You should not use the AbsolutePosition property in
place of bookm arks. Depending on the options you select w hen you open your
recordset, the actual record pointed to by the AbsolutePosition m ay change as
other records are added and deleted from the recordset. Don’t assum e that if you
haven’t added or deleted a record, this value w on’t change. Rem em ber —depending on the type of cursor you select, changes m ade by other database users m ay
affect the value of AbsolutePosition associated w ith a particular row.

Searching, Sorting, and Filtering
Ano ther c o mmo n need is the ability to find and o rganize the info rmatio n within a
rec o rdset. The Recordset o bjec t inc ludes a metho d to find a partic ular ro w by
searc hing fo r a value, and a metho d to so rt the rec o rds c o ntained in the rec o rdset
by a spec ified list o f fields.

Chapter 15 ✦ Working with Recordsets —Part II

Finding a row
One c o mmo n pro blem with retrieving a large number o f rec o rds is trying to find a
partic ular value in the Recordset. The easiest way to address this pro blem is to
use the Find metho d.
The Find metho d allo ws yo u to spec ify a searc h string c o nsisting o f a c o lumn
name, a relatio nal o perato r, and a value. If the value is a string, it must be enc lo sed
in either single quo tes ( ‘ ) o r po und signs ( # ). Do uble quo tes ( “ ) may no t be used.
Po und signs must enc lo se date values.
If yo u use the Like o perato r, yo u may also use an asterisk ( * ) as a wild c ard c harac ter in any string value. Ho wever, the asterisk must be the last c harac ter in the
value o r the o nly c harac ter in the value. Otherwise a run-time erro r will o c c ur.
The Find metho d has several arguments in additio n to the searc h c o nditio n.
Spec ify the number o f ro ws to skip befo re beginning yo ur searc h; o therwise, the
searc h will begin with the c urrent ro w. So , yo u sho uld spec ify a value o f o ne if yo u
want to find the next o c c urrenc e o f a value.
Yo u c an also spec ify whether yo u want to searc h bac kwards (to ward the beginning)
o r fo rwards (to ward the end) o f the rec o rdset, and yo u may spec ify a bo o kmark
fro m where the searc h will begin.
Like mo st o f the Recordset metho ds I’ve talked abo ut so far, yo u simply c all the
metho d with the list o f arguments yo u wish to use, and inc lude the appro priate
erro r c hec king to prevent a run-time erro r fro m o c c urring if yo u c an’t find the
rec o rd o r yo ur searc h c o nditio n c o ntains an erro r (see Listing 15-7).

Listing 15-7: The Command10_Click event of Recordset
M ovement Demo
Private Sub Command10_Click()
On Error Resume Next
StatusBar1.SimpleText = “”
Err.Clear
Customers.Find Text17.Text, 1
If Err.Number 0 Then
WriteError
End If
End Sub

315

316

Part III ✦ Hardcore ADO

Note

For client-side cursors only: The Seek m ethod provides an alternative to the
Find m ethod, but is only available w hen you are using client-side cursors (discussed in Chapter 14). You begin by specifying the nam e of an index in the Index
property and then supplying a list of values to search for that corresponds to the
colum ns in the index (i.e., if your index has only one colum n, only one value m ay
be supplied). Note that not all providers support this feature, including the one for
SQL Server, so you m ay w ant to use the Supports m ethod to determ ine if the
Seek m ethod is supported.

Sorting rows
The Sort pro perty c o ntains the list o f c o lumns that are used to so rt yo ur rec o rdset. Thus, o ne way yo u c an so rt the rec o rdset in the sample pro gram is by setting
the Sort pro perty to the fo llo wing value:

State, Name Desc
This so rt key will so rt the ro ws by State in asc ending o rder and then by the Name
c o lumn in desc ending o rder.
The Sort pro perty is available o nly fo r c lient-side rec o rdsets, whic h means yo u
may want to do a little extra erro r c hec king, espec ially if yo u use multiple c urso r
types. The erro r message that wo uld no rmally be issued (“Objec t o r pro vider is no t
c apable o f perfo rming requested o peratio n”) do esn’t fully desc ribe what c aused the
erro r.
Listing 15-8 c o ntains so me sample c o de that will so rt the info rmatio n in a rec o rdset.
The ro utine begins by getting the so rt key fro m the fo rm and assigning it to the
Sort pro perty. Then I c hec k fo r erro rs and display the appro priate erro r message.
An erro r c o de o f 3251 implies that the user attempted to so rt the rec o rdset witho ut
using a c lient-side c urso r.

Listing 15-8: The Command13_Click event in Recordset
M ovement Demo
Private Sub Command13_Click()
On Error Resume Next
Err.Clear
Customers.Sort = Text19.Text
If Err.Number = 3251 And _
Customers.CursorLocation = adUseServer Then
StatusBar1.SimpleText = _

Chapter 15 ✦ Working with Recordsets —Part II

“Can’t sort while using server cursors.”
ElseIf Err.Number 0 Then
WriteError
End If
End Sub

Filtering rows
One o f my favo rite to o ls available in a Recordset o bjec t — o ne that will help yo u
lo c ate a partic ular rec o rd — is the Filter pro perty. Only tho se ro ws that meet the
filter c riteria yo u spec ify will be visible in the rec o rdset.
Yo u c an filter yo ur rec o rdset using a string whic h is similar to the c o nditio n yo u
wo uld spec ify in the Where c lause o f a Select statement. A co nditio n is c o mpo sed
o f o ne o r mo re simple expressio ns c o mpo sed o f c o lumn names, relatio nal o perato rs, and values that c an be gro uped to gether, as in this example:

State = ‘MD’ And CustomerId > 100
To remo ve a filter, simply set the Bookmark pro perty to zero o r the c o nstant
adFilterNone. The o riginal c o ntents o f the rec o rdset will no w be ac c essible.
If yo u c reate an array o f bo o kmark values and assign it to the Filter pro perty, o nly
the ro ws in the array will be visible in the rec o rdset. Yo u c an also assign the Filter
pro perty a value fro m the FilterGroupEnum data type. Aside fro m adFilterNone,
these values are used primarily fo r reviewing the results o f batc h updates, whic h I’ll
talk abo ut in the next c hapter.
Caution

Why did it change?: Using the Filter property w ill change the values in the
AbsolutePosition, AbsolutePage, RecordCount, and PageCount properties for a specific row. If you need to rem em ber w here a particular row is located,
you should use the Bookmark property, w hich w ill rem ain unchanged no m atter
w hat the value of the Filter property.

Listing 15-9 desc ribes a ro utine that applies the value spec ified in the Text16 text
bo x as a filter to the Customers rec o rdset. If the length o f the text is zero , then I
explic itly remo ve the filter by assigning the Filter pro perty the value
adFilterNone.

317

318

Part III ✦ Hardcore ADO

Listing 15-9: The Command9_Click event in Recordset
M ovement Demo
Private Sub Command9_Click()
On Error Resume Next
StatusBar1.SimpleText = “”
Err.Clear
If Len(Text16.Text) = 0 Then
Customers.Filter = adFilterNone
Else
Customers.Filter = Text16.Text
End If
If Err.Number 0 Then
WriteError
End If
End Sub

Collecting recordset information
There are two events asso c iated with c hanging the po sitio n o f the c urrent rec o rd
po inter in the Recordset o bjec t. I talked abo ut the WillMove event earlier in this
c hapter (see Listing 15-4), and no w I want to talk abo ut the MoveComplete event.
This is an exc ellent plac e to display the c urrent status o f a rec o rdset.
Tip

You don’t need to do this: In this sam ple program , I w anted to dem onstrate
clearly how the various status fields change w hile you perform various tasks using
a Recordset. The easiest w ay for m e to do this w as to trap the state of the object
using the MoveComplete event. How ever, this isn’t som ething you need to do in
your ow n program s. You can easily test the various properties directly after you
perform a task. Thus, you don’t need to use the MoveComplete event.

Listing 15-10: The Customers_M oveComplete event in
Recordset M ovement Demo
Private Sub Customers_MoveComplete( _
ByVal adReason As ADODB.EventReasonEnum, _
ByVal pError As ADODB.Error, _
adStatus As ADODB.EventStatusEnum, _

Chapter 15 ✦ Working with Recordsets —Part II

ByVal pRecordset As ADODB.Recordset)
On Error Resume Next
If Customers.BOF And adStatus = adStatusErrorsOccurred Then
Text5.BackColor = RGB(255, 0, 0)
ElseIf Customers.BOF Then
Text5.BackColor = RGB(255, 255, 0)
Else
Text5.BackColor = RGB(0, 0, 0)
End If
If Customers.EOF And adStatus = adStatusErrorsOccurred Then
Text6.BackColor = RGB(255, 0, 0)
ElseIf Customers.EOF Then
Text6.BackColor = RGB(255, 255, 0)
Else
Text6.BackColor = RGB(0, 0, 0)
End If
Text9.Text = FormatNumber(Customers.AbsolutePosition, 0)
Text10.Text = FormatNumber(Customers.RecordCount, 0)
Text11.Text = FormatNumber(Customers.AbsolutePage, 0)
Text12.Text = FormatNumber(Customers.PageCount, 0)
Err.Clear
Text13.Text = Customers.Bookmark
If Err.Number 0 Then
Text13.Text = “The bookmark isn’t available.”
End If
End Sub

This ro utine starts o ut by displaying info rmatio n abo ut the BOF and EOF flags. The
c o de fo r bo th is the same. There are three po ssible c o nditio ns. First, if the c urrent
rec o rd po inter is no t po inting to either BOF o r EOF, I have a no rmal rec o rd and
do n’t want to do anything. Sec o nd, if the c urrent rec o rd po inter is po inting to either
BOF o r EOF, then I want to turn the bac kgro und o f the asso c iated text bo x to yello w
( RGB(255,255,0)). The third c o nditio n arises if the mo st rec ent mo ve o peratio n
had an erro r. I assume that the c urrent rec o rd po inter was at BOF o r EOF befo re
the mast o peratio n. Then I want to display the bac kgro und in red ( RGB(255,0,0)).

319

320

Part III ✦ Hardcore ADO

This means that the user attempted to mo ve past the BOF o r EOF marker. The easiest way to implement this in c o de is to start with the last c o nditio n (bec ause it’s
the mo st restric tive) and wo rk my way bac kwards.
After I set the BOF and EOF flags, I display the pro perties fo r AbsolutePosition,
RecordCount, AbsolutePage, and PageCount. Then I attempt to grab the c urrent
bo o kmark. If the Bookmark isn’t available, I’ll trigger a run-time erro r and display a
message that indic ates this.

Getting Information From Fields
Mo ving aro und a rec o rdset is impo rtant, but retrieving info rmatio n fro m a field is
equally impo rtant. Eac h o f the sample pro grams in Part III o f this bo o k has used the
Fields c o llec tio n and so me Field o bjec ts to display data. In so me c ases, this was
do ne explic itly thro ugh statements like this:

Text1.Text = FormatNumber(rs.Fields(0).Value, 0)
while o ther pro grams used the Recordset o bjec t as the data so urc e and bo und
vario us c o ntro ls o n the fo rm to the individual Field o bjec ts.

Binding a field to a control
The same pro perties that yo u use to bind a c o ntro l to the ADO Data Co ntro l are
also used to bind to a Recordset. Ho wever, unlike the ADO Data Co ntro l, yo u c an’t
bind the c o ntro ls at design time, sinc e the Recordset o bjec t do esn’t exist. So yo u
need to set these pro perties at runtime. In fac t, yo u c an o nly set these pro perties
while the Recordset o bjec t is o pen. This means that if yo u c lo se a rec o rdset and
reo pen it, yo u need to rebind all o f yo ur c o ntro ls.
Sho wn belo w is a c o de fragment that c o ntains the key pro perties yo u need to set in
o rder to bind a field to a c o ntro l. The DataField pro perty c o ntains the name o f the
c o lumn yo u want to bind the c o ntro l to , while the DataSource pro perty c o ntains
an o bjec t referenc e to the Recordset o bjec t. No te that yo u must use the Set statement to make this assignment.

Text3.DataField = “Name”
Set Text3.DataSource = Customers

Accessing field values
Assuming that yo u do n’t want to bind yo ur data using a c o ntro l, yo u c an ac c ess
eac h field direc tly using the Fields c o llec tio n and the Field o bjec t.

Chapter 15 ✦ Working with Recordsets —Part II

Referencing a field’s value
Visual Basic pro vides many different ways fo r yo u to retrieve a value fro m a Field
o bjec t. Yo u c an use the traditio nal o bjec t-o riented way by spec ifying the Recordset
o bjec t and wo rking yo ur way do wn to the lo west level o bjec t. The fo llo wing expressio ns take advantage o f the default pro perties o f the Recordset o bjec t and the
Fields and Items c o llec tio ns to return the value o f the “Name” field. No te that yo u
c an replac e the value “Name” with the numeric po sitio n o f the field in the Fields
c o llec tio n.

Customers.Fields.Items(“Name”).Value
Recordset.Fields.Items(“Name”)
Recordset.Fields(“Name”).Value
Recordset.Fields(“Name”)
Recordset(“Name”)
Tip

Fewer is faster: The few er periods (.) included in an object reference, the faster it
w ill run. Each period m eans that a call m ust be m ade to the object to determ ine if
the follow ing property is valid and to get a reference to the code that w ill process
it. The inform ation needed to call the object’s default property is autom atically
retrieved w hen the object is created.

An alternate way to retrieve a value is by using an exc lamatio n mark (!), as sho wn
belo w.

Recordset!Name
No te that in this fo rmat, the field name must be spec ified witho ut single quo tes (‘)
and spac es. Yo u also c an’t use a numeric referenc e to the field. Ho wever, if yo u
enc lo se the field name using square brac kets ([]), yo u c an use any o f these values
as sho wn belo w.

Recordset![First Name]

Other field values
There are two o ther value pro perties asso c iated with a Field o bjec t: the
OriginalValue and the UnderlyingValue. The OriginalValue field c o ntains the
value o f the Field o bjec t as it was when it was retrieved fro m the database. This
value is useful when yo u want to resto re the o riginal value after yo u c hange it. The
UnderlyingValue c o ntains the value fo r this field in this ro w, as it c urrently exists
in the database when yo u ac c ess this pro perty.

Working with large values
When yo u dec lare a c o lumn as NText, Text, o r Image , yo u c an’t use the Value pro perty to ac c ess the data. Instead, yo u must use the GetChunk metho d to retrieve

321

322

Part III ✦ Hardcore ADO

info rmatio n fro m the field, and the AppendChunk metho d to save values to the field.
These metho ds wo rk basic ally the same fo r all three types o f data, so I’m just go ing
to talk abo ut Image fields in this sec tio n. Mo st peo ple are go ing to use them fo r
graphic images, binary do c uments (suc h as RTF files, Exc el Wo rksheets, and so o n)
o r o ther fo rms o f binary data.

Bound controls
Chanc es are, the reaso n yo u’re using large c o lumns is that yo u want to ho ld an
image o r a large text do c ument. If that’s true, then yo u sho uld take advantage o f
c o ntro ls like the Image, Picture, and the Rich Text Box that are c apable o f
being bo und to a field in a rec o rdset and c an handle large vo lumes o f data.
Imperfect images: Changing the im age in either the Picture control or the
Image control w ill not update the field in the recordset. You m ust explicitly load

Note

the im age into the field. Even if you w ere able to save the im age in the control,
you w ould be better off storing the im age in either .GIF or .JPG form at in the
database, rather than storing the uncom pressed bit m ap im age used by the
Picture and Image controls.

Loading images
One o f the mo st c o mmo n questio ns I’ve heard peo ple ask is ho w to lo ad an image
into an Image database field fro m a Visual Basic pro gram. The answer is sho wn in
Listing 15-11. The real tric k is to use a Byte array and Redim the size so that the
array has the same number o f bytes as the image file. Then it’s merely a matter o f
o pening the file fo r binary ac c ess and using the Get statement to read the image
into the array in a single c hunk. Onc e yo u’ve lo aded the image into memo ry, yo u
c an use the AppendChunk metho d to c o py it into the Field o bjec t, and then
Update to save it to the database.
On the
CD-ROM

You can find the Recordset Update Dem o program on the CD-ROM in the
\VB6DB\Chapter16\RecordsetUpdateDemo directory.

Listing 15-11: The Command14_Click event in Recordset
Update Demo
Private Sub Command14_Click()
Dim f As String
Dim img() As Byte
f = InputBox(“Enter image file name:”)

Chapter 15 ✦ Working with Recordsets —Part II

f = App.Path & “\” & f
If Len(Dir(f)) > 0 Then
Open f For Binary Access Read As #1
ReDim img(FileLen(f) - 1)
Get #1, , img()
Close #1
Images(“Image”).AppendChunk img
Image1.Picture = LoadPicture(f)
Else
Image1.Picture = LoadPicture()
End If
End Sub

Note

Zero counts, too: When m oving data from a file to a Byte array, rem em ber that
the array w ill start w ith zero, so the size of the array m ust be one byte less than
size of the file to allow for the zeroth byte in the array.

While it is po ssible to use a lo o p like the o ne sho wn belo w to lo ad an image, I feel
that it isn’t wo rth the effo rt fo r files smaller than a megabyte o r so . Ho wever, yo u
c an use the fo llo wing c o de to replac e the statements in Listing 15-11 fro m the Open
statement to the Close statement to perfo rm a lo o p. No te that this ro utine begins
by c o pying the o dd size blo c k first and then c o pying c hunks in a fixed blo c k size.
Otherwise, yo u’d have to keep trac k o f the number o f bytes transferred to determine when yo u are abo ut to read the last blo c k so yo u may ReDim the Byte array
in o rder to transfer o nly the appro priate amo unt o f data.

Open f For Binary Access Read As #1
ReDim img(FileLen(f) Mod 1024 - 1)
Get #1, , img()
Do While Not EOF(1)
Images.Fields(“Image”).AppendChunk img
ReDim img(1023)
Get #1, , img
Loop
Close #1

Saving images
The c o de to save the value in a lo ng field isn’t very different than it is to lo ad the
data into the field. If po ssible, it’s best to try to deal with the data in a single c hunk,
as sho wn in Listing 15-12.

323

324

Part III ✦ Hardcore ADO

Listing 15-12: The Command15_Click event in Recordset
Update Demo
Private Sub Command15_Click()
Dim f As String
Dim img() As Byte
f = InputBox(“Enter image file name:”)
f = App.Path & “\” & f
ReDim img(Images.Fields(“Image”).ActualSize - 1)
Open f For Binary Access Write As #1
img = Images.Fields(“Image”).GetChunk(UBound(img) + 1)
Put #1, , img
Close #1
End Sub

Thoughts on Designing Database Applications
There are tw o basic w ays to design a database application. One w ay is to perm it the user to
scroll through from one record to another through the entire recordset. The second w ay is
to ask the user for a key value, w hich w ill return only the records related to the key. Both
approaches have strengths and w eaknesses, and you can build effective program s using
either technique.
The first m ethod w orks w ell if you w ant to use the ADO Data Control. The ADO Data Control
opens a connection to the database and its Recordset object as soon as the form containing it is show n. How ever, this isn’t practical for large, m ulti-user applications. It can be
difficult for a user to find a particular row in the data, w hile at the sam e tim e consum ing a
lot of database resources. How ever, this approach is ideal for sm all databases, w here the
num ber of records is sm all enough that the scrolling ability is appreciated and you have a
sufficiently sm all num ber of users that w on’t overw helm the database server.
A better approach for large databases is one that allow s the user to retrieve data based on
a key value, such as Custom erId or IntentoryId. If the user doesn’t know the exact value,
they can perform a lim ited search on a field like Nam e to get the appropriate key value. This
approach has the advantage of using few er resources on the database server, since you are
accessing far few er records at any point in tim e. It also allow s you to think of your application in term s of transactions. This allow s you to take advantage of stored procedures and
COM+ transactions, w hich w ould allow you to isolate the application logic, and in turn
m akes your application far m ore scalable. This approach is the only w ay you can build
applications that run in a user’s brow ser.

Chapter 15 ✦ Working with Recordsets —Part II

Summary
In this c hapter yo u learned the fo llo wing:

✦ Yo u c an use the Fields c o llec tio n to ac c ess the c o llec tio n o f c o lumns
retrieved fro m the database.

✦ Yo u c an use the Field o b jec t to ac c ess the info rmatio n asso c iated with a
single c o lumn.

✦ Yo u c an use many different metho ds to selec t a rec o rd fro m the rec o rdset,
inc luding MoveFirst, MoveNext, MovePrev, MoveLast, Move, Bookmark,
AbsoluteRecord and AbsolutePage.

✦ Yo u c an use the Sort pro perty to so rt the info rmatio n in a rec o rdset and the
Find metho d to lo c ate a partic ular ro w in a rec o rdset.

✦ Yo u c an use the GetChunk and AppendChunk metho ds to retrieve and sto re
info rmatio n in large values in yo ur rec o rdset, suc h as images.







325