Working with
Recordsets —
Part I
O
f all o f the o bjec ts in ADO, the Recordseto bjec t is the o ne yo u’ll use the mo st. It c o ntains the ac tual data fro m yo ur database. Yo u c an use this o bjec t to retrieve, insert, update, and delete info rmatio n fro m the database. It c an be used as a data so urc e fo r o ther c o ntro ls, just like the ADO Data Co ntro l. In fac t the ADO Data Co ntro l expo ses a refer-enc e to the Recordseto bjec t, yo u c an ac c ess the info rmatio n c o ntained in the underlying rec o rdset direc tly.This c hapter and the next two are dedic ated to the to pic o f rec o rdsets. In this c hapter, I’m go ing to disc uss the vario us pro perties, metho ds, and events in a Recordseto bjec t. Then I’ll disc uss ho w to o pen and use a Recordseto bjec t. In the next c hapter, I’ll c o ntinue disc ussing the Recordseto bjec t and c o ver ho w to mo ve aro und inside rec o rdsets and ho w to ac c ess the individual fields. Finally, in Chapter 16 I’ll c o ver the issues related to updating the data c o ntained in a rec o rdset.
The Recordset Object
The Recordseto bjec t c o ntains the set o f ro ws retrieved fro m a database query. Vario us pro perties and metho ds instruc t the OLE DB pro vider o n ho w the ro ws sho uld be returned fro m the database and ho w the pro vider sho uld handle updates and lo c king to ensure pro per ac c ess to the data. Other pro perties and metho ds in the Recordseto bjec t allo w yo u to ac c ess the set o f ro ws retrieved.
1 4
1 4
✦
✦
✦
✦
In This Cha pter
The Reco rdset o bject
Explo ring vario us types o f lo cks
Cho o sing a curso r type
O pening a reco rdset
Birds of a Feather aren’t at the first record of the Recordset: There is a com m on m isconception that w hen BOF is TRUE, you are at the first record of the
Recordset. This isn’t true. When BOFis TRUE, the current record pointer is before the first record in the Recordset, and there isn’t a current record. The sam e is true for EOF, except in that case, the current record pointer is beyond the last record in the Recordset.
Recordset object properties
Table 14-1 lists the pro perties asso c iated with the Recordseto bjec t. Tables 14-2 thro ugh 14-8 c o ntain additio nal info rmatio n abo ut individual pro perties in the
Recordseto bjec t.
Table 14-1
Properties of the Recordset Object
Property Description
AbsolutePage A Longvalue containing the absolute page num ber of the current record in the Recordsetranging from 1 to PageCount. This value m ay also be adPosBOF(-2) if the current record is at the beginning of the file or adPosEOF(-3) if the current record is at the end of the file. A value of adPosUnknown(-1) m ay be used if the Recordsetis em pty or the provider doesn’t support this property.
AbsolutePosition A Longvalue containing the absolute position of the current record in the Recordsetranging from 1 to RecordCount. This value m ay also be adPosBOF(-2) if the current record is at the beginning of the file or adPosEOF(-3) if the current record is at the end of the file. A value of adPosUnknown(-1) m ay be used if the Recordsetis em pty or the provider doesn’t support this property.
ActiveCommand An object reference to the Commandobject that created the
Recordset. If the Recordsetw asn’t created using a Command
object, this property w ill have a Nullobject reference.
ActiveConnection A Variantarray containing either a Stringvalue w ith a valid connection string or an object reference to a Connection
object.
BOF A Booleanvalue that is TRUEw hen the current record position is before the first record in the Recordset.
Property Description
Bookmark A Variantthat sets or returns a value that uniquely identifies the current record in the current Recordsetobject. You can save this property and m ove to a different record. Then you can restore the value to return back to the original record.
CacheSize A Longvalue containing the num ber of records kept in the provider’s cache. The default value for this property is 1.
CursorLocation An enum erated value that indicates w here the cursor is m aintained (see Table 14-2).
CursorType An enum erated value that specifies the type of cursor that w ill be used on the Recordset. (see Table 14-3).
DataMember A Stringcontaining the nam e of the data m em ber that w ill be retrieved using the DataSourceproperty. Works w ith the
DataSourceproperty to bind a Recordsetto a control.
DataSource An object reference that indicates the data source w hen using bound controls.
EditMode An enum erated value containing the edit m ode of the current record (see Table 14-4).
EOF A Booleanvalue that is TRUEw hen the current record position is after the last record in the Recordset.
Fields An object reference to a Fieldscollection containing the fields associated w ith the current record.
Filter A Variantvalue containing one of the follow ing: a String
value containing an expression sim ilar to that in a Whereclause that w ill select only those records m eeting the specified criteria; an Arrayof bookm arks; or a Longvalue selected from Table 14-5.
Index A Stringcontaining the nam e of an index that is used in conjunction w ith the Seekm ethod.
LockType An enum erated value containing the locking m ode used by the
Recordsetw hen retrieving records (see Table 14-6).
MarshalOptions An enum erated value that indicates how records are to be m arshaled back to the server. Applies only to Recordsetsw ith client-side cursors (discussed later in this chapter). The default value is adMarshalAll(0), w hich returns all row s back to the server for processing, w hile adMarshalModifiedOnly(1) returns only the m odified row s.
Table 14-1
(continued)
Property Description
MaxRecords A Longvalue that specifies the m axim um num ber of row s to be returned. A value of zero im plies there is no m axim um lim it.
PageCount A Longvalue containing the num ber of pages of data in the
Recordset. The num ber of records in a page is specified by the
PageSizeproperty, w hile the current page num ber is specified in the AbsolutePageproperty.
PageSize A Longvalue containing the num ber of records in a single page.
Properties An object reference to a Propertiescollection containing provider specific inform ation.
RecordCount A Longvalue containing the num ber of records retrieved. If the provider is not able to determ ine the num ber of records retrieved or a forw ard-only cursor is selected, this property w ill have a value of –1.
Sort Specifies a list one or m ore of field nam es on w hich the
Recordsetw ill be sorted. Multiple fields need to be separated by com m as, and each field nam e m ay be follow ed by ASC or DESC to sort the fields in either ascending or descending order. The syntax is basically the sam e as the Order Byclause in the
Selectstatem ent. This property is only valid w hen you use a client-side cursor (discussed later in this chapter).
Source A Variantw hich can either be a Stringcontaining the nam e of a table, a SQL Statem ent, or the nam e of a stored procedure or an object reference to a Commandobject.
State A Longvalue describing the current state of the Recordset
object. Multiple values can be com bined to describe the current state (see Table 14-7 for a list of values).
Status A Longvalue describing the current status of a record in a batch update (see Table 14-8).
Table 14-2
Values for CursorLocation
Constant Value Description
adUseNone 1 Doesn’t use cursor services. This value should not be selected and exists solely for com patibility.
adUseServer 2 The cursor services are provided by the data provider.
adUseClient 3 The cursor services are provided by a local cursor library, w hich m ay provide m ore features than the data provider’s cursor library provides.
Table 14-3
Values for CursorType
Constant Value Description
adOpenUnspecified -1 The type of cursor isn’t specified.
adOpenForwardOnly 0 A forw ard-only cursor is used, w hich perm its you only to scroll forw ard through the records in the
Recordset.
adOpenKeyset 1 A keyset cursor is used, w hich is sim ilar to a dynam ic cursor, but doesn’t perm it you to see records added by other users.
adOpenDynamic 2 A dynam ic cursor is used, w hich allow s you to see records added by other users, plus any changes and deletions m ade by other users.
Table 14-4
Values for EditM ode
Constant Value Description
adEditNone 0 Editing is not active; the data in the current record hasn’t been changed.
adEditInProgress 1 The data in the current record has been changed, but not yet saved.
adEditAdd 2 The AddNewm ethod has been used to create a new record, but the record hasn’t been saved yet.
adEditDelete 4 The current record has been deleted.
Table 14-5
Values for Filter
Constant Value Description
adFilterNone 0 Rem oves all filtering criteria.
adFilterPendingRecords 1 Selects only those records that have been changed, but not sent to the server for updating. Applies to batch update m ode only.
adFilterAffectedRecords 2 Selects only those records that have been affected by the last CancelBatch,Delete,
Resync, or UpdateBatch.
adFilterFetchedRecords 3 Selects only those records in the current cache.
adFilterConflictingRecords 5 Selects only those records that have failed the last batch update.
Table 14-6
Values for LockM ode
Constant Value Description
adLockUnspecified -1 The type of locking isn’t specified.
Constant Value Description
adLockPessimistic 2 Records are locked at the data source record by record once the data in the record has been changed.
adLockOptimistic 3 Records are locked only w hen you call the
UpdateMethod.
adLockBatchOptimistic 4 Records are not locked, and conflicts w ill be returned for resolution after the
UpdateBatchm ethod has com pleted.
Table 14-7
Values for State
Constant Value Description
adStateClosed 0 TheCommandobject is closed.
adStateOpen 1 The Commandobject is open.
adStateConnecting 2 The Commandobject is connecting to the database.
adStateExecuting 4 The Commandobject is executing.
adStateFetching 8 Row s are being retrieved.
Table 14-8
Values for Status
Constant Value Description
adRecOK 0 The record w as successfully updated.
adRecNew 1 The record is new.
adRecModified 2 The record has been m odified.
adRecDeleted 4 The record has been deleted.
adRecUnmodified 8 The record has not been m odified.
adRecInvalid 16 The record w asn’t saved because its bookm ark w as invalid.
Table 14-8
(continued)
Constant Value Description
adRecMultipleChanges 64 The record w asn’t saved because it w ould have affected m ultiple records.
adRecPendingChanges 128 The record w asn’t saved because it refers to a pending insert.
adRecCanceled 256 The record w asn’t saved because the operation w as canceled.
adRecCantRelease 1024 The new record w asn’t saved because the existing record w as locked.
adRecConcurrencyViolation 2048 The record w asn’t saved because optim istic concurrency w as in use.
adRecIntegrityViolation 4096 The record w asn’t saved because the data violated an integrity constraint.
adRecMaxChangesExceeded 8192 The record w asn’t saved because there w ere too m any pending changes.
adRecObjectOpen 16384 The record w asn’t saved because of a conflict w ith an open storage object.
adRecOutOfMemory 32768 The record w asn’t saved because the com puter ran out of m em ory.
adRecPermissionDenied 65536 The record w asn’t saved because the user doesn’t have sufficient perm issions.
adRecSchemaViolation 131072 The record w asn’t saved because it violates the underlying database structure.
adRecDBDeleted 262144 The record has already been deleted from the data source.
Recordset object methods,
The Recordseto bjec t c o ntains many different metho ds to manipulate the data in the Recordset.
Sub AddNew ([FieldList], [Values])
The AddNewmetho d is used to add a new empty rec o rd to the Recordset. This will set the EditModepro perty to adEditAdd. After assigning values to eac h o f the fields, yo u c an use the Updatemetho d to save the c hanges. If yo u spec ify the
In batc h update mo de, yo u pro c eed as abo ve. The c hanges will be saved lo c ally in the Recordset, but no t sent to the server. After adding the last rec o rd o f the batc h, yo u must c all the UpdateBatchmetho d to save the c hanges to the database. Then yo u sho uld set the Filterpro perty to adFilterConflictingand take the appro -priate ac tio n fo r the rec o rds that weren’t po sted to the database pro perly.
FieldListis o ptio nal and is either a Stringvalue c o ntaining a single field name o r a String Arrayc o ntaining a list o f field names.
Valuesis an o ptio nal Variantc o ntaining a single value c o rrespo nding to a single field name o r Arrayo f values c o rrespo nding to the Arrayo f field names.
Sub Cancel( )
The Cancelmetho d is used to terminate an async hro no us task started by the Open
metho d.
Sub CancelBatch ([AffectRecords As AffectEnum = adAffectAll])
The CancelBatchmetho d is used to c anc el a pending batc h update. If the c urrent rec o rd hasn’t been saved, CancelBatchwill auto matic ally c all CancelUpdateto disc ard any c hanges. As with all batc h o peratio ns, yo u sho uld verify the Status
pro perty fo r all o f the affec ted rec o rds to ensure that they were pro perly c anc eled.
AffectRecordsis an enumerated type that desc ribes whic h rec o rds will be affec ted by the c anc el o peratio n ( see Table 14-9) .
Table 14-9
Values for AffectRecords
Constant Value Description
adAffectCurrent 1 Affects only the current record in the
Recordset.
adAffectGroup 2 Affects only those records selected by the current value of the Filterproperty.
adAffectAll 3 Affects all records in the Recordset.
adAffectAllChapters 4 Affects all records in all chapters of the
Sub CancelUpdate ( )
The CancelUpdatemetho d is used to abando n all o f the c hanges made to a rec o rd and to resto re its values to the o riginal values befo re the Updatemetho d is c alled. If yo u use CancelUpdateto undo a ro w added with the AddNewmetho d, the newly added ro w will be disc arded, and the c urrent rec o rd will bec o me the ro w that was the c urrent ro w befo re the AddNewmetho d was used.
Function Clone ([LockType As LockTypeEnum =
adLockTypeUnspecified]) As Recordset
The Clonemetho d is used to c reate a duplic ate o f a Recordseto bjec t. LockType
allo ws yo u to spec ify that the new Recordseto bjec t is read-o nly. The o nly permis-sible values are adLockUnspecifiedand adLockReadOnly.
Sub Close
The Closemetho d c lo ses an o pen Recordsetand frees all o f its asso c iated reso urc es. If yo u are editing a rec o rd in the Recordset, an erro r will o c c ur, and the
Closemetho d will be terminated. Yo u need to c all either Updateo r CancelUpdate
first. If yo u are wo rking in batc h mo de, all c hanges sinc e the last UpdateBatchwill be lo st.
Sub CompareBookmarks(Bookmark1, Bookmark2) As CompareEnum
The CompareBookmarksmetho d c o mpares two bo o kmarks and returns info rmatio n abo ut their relative po sitio ns. Bo th bo o kmarks must c o me fro m the same Recordset
o bjec t o r fro m c lo nes o f the same Recordseto bjec t. Table 14-10 c o ntains a list o f po ssible return values.
Bookmark1and Bookmark2are valid bo o kmarks.
Table 14-10
Values for CompareEnum
Constant Value Description
adCompareLessThan 0 The first bookm ark is before the second bookm ark.
adCompareEqual 1 The tw o bookm arks are equal.
adCompareGreaterThan 2 The first bookm ark is after the second bookm ark.
adCompareNotEqual 3 The tw o bookm arks are different and not ordered.
Sub Delete ([AffectRecords As AffectEnum = adAffectCurrent])
The Deletemetho d is used to delete o ne o r mo re rec o rds fro m a Recordset
o bjec t.
AffectRecordsis an enumerated type that desc ribes whic h rec o rds will be deleted by this o peratio n ( see Table 14-9) . The default value is adAffectCurrent,
whic h means o nly the c urrent ro w will be deleted.
Sub Find (Criteria As String, [SkipRows As Long], [SearchDirection As
SearchDirectionEnum = adSearchForward], [Start])
The Findmetho d is used to lo c ate the spec ified c riteria in a Recordset. No te that yo u must have a valid c urrent rec o rd befo re c alling the Findmetho d, so yo u may want to c all MoveFirstbefo re using this metho d.
Criteriais a Stringvalue that spec ifies a field name, a c o mpariso n o perato r, and a value. Only o ne field name may be spec ified.
SkipRowsis a Longvalue that spec ifies the number o f ro ws to skip relative to the c urrent ro w befo re starting the searc h. The default value is zero , whic h means the searc h will begin with the c urrent ro w.
SearchDirectionis an enumerated type that indic ates the direc tio n o f the searc h. Yo u c an spec ify adSearchForward( 1) to searc h to the end o f the Recordset, o r yo u c an spec ify adSearchBackward( -1) to searc h to the beginning o f the
Recordset.
Startis a Variantc o ntaining a bo o kmark fo r the first rec o rd to be searc hed.
Function GetRows ([Rows As Long = -1], [Start], [Fields]) As Variant
The GetRowsmetho d retrieves multiple rec o rds fro m a Recordseto bjec t into a two -dimensio nal array.
Rowsis the numb er o f ro ws to b e retrieved. The default value is adGetRowsRest
( -1) , whic h will retrieve the rest o f the ro ws in the tab le.
Startis an o ptio nal Variantc o ntaining a bo o kmark fo r the first ro w to be retrieved. If yo u do no t spec ify values fo r bo th Rowsand Start, all o f the ro ws in the table will be retrieved.
Fieldsis an o ptio nal Variantc o ntaining a Stringwith a single field name, a
Function GetString ([StringFormat As StringFormatEnum =
adClipString], [NumRows As Long = -1], [ColumnDelimiter As String],
[RowDelimiter As String], [NullExpr As String]) As String
The GetStringmetho d returns a Stringc o ntaining the values fro m the
Recordset.
StringFormatis a Longvalue c o ntaining the value adClipString( 2) . This is the o nly legal value fo r this metho d.
NumRowsis a Longvalue c o ntaining the number o f ro ws to be saved in the string. A value o f –1 means that all o f the ro ws will be retrieved.
ColumnDelimiteris a Stringc o ntaining the delimiter to be used between eac h c o lumn. If no t spec ified, a tab c harac ter will be used.
RowDelimiteris a Stringc o ntaining the delimiter to be used between eac h ro w. If no t spec ified, a c arriage return c harac ter will be used.
NullExpris a Stringc o ntaining the value to be displayed in plac e o f a null value. If it is no t spec ified, no thing will be o utput.
To CSV or not to CSV: I often find it useful to create Com m a Separated Value files from a database. These files can be easily im ported into a program like Excel for analysis and testing. The GetStringm ethod m akes it easy to w rite a program to save your data into a CSV file. Sim ply specify a com m a for ColumnDelimiter
and vbCrLffor the RowDelimiter.
Sub M ove (NumRecords As Long, [Start])
The Movemetho d is used to mo ve the c urrent rec o rd po inter to a different lo c a-tio n in the Recordset. If the Recordsetis already at BOF, an attempt to mo ve b ac kwards will generate a runtime erro r. Similarly, if the Recordsetis already at
EOF, an attempt to mo ve fo rward will also generate a runtime erro r.
NumRecordsis a Longvalue c o ntaining the number o f rec o rds to be mo ved. If a value o f zero is spec ified, the c urrent rec o rd po inter remains unc hanged, and the c urrent rec o rd is refreshed. A value greater than zero means that the c urrent rec o rd po sitio n will be mo ved to the end o f the Recordset, while a value less than zero will mo ve the c urrent rec o rd po inter to wards the beginning o f the Recordset.
Startis a Variantc o ntaining a bo o kmark that will be used as the starting po sitio n fo r the mo ve.
Forward-NOT-only:Even if you specify a forw ard-only cursor, you can still m ove backw ard using the Move m ethod, as long as you do not m ove beyond the records in the current cache.
Sub M oveFirst ( )
The MoveFirstmetho d mo ves the c urrent rec o rd po inter to the first rec o rd in the
Recordset.
M oveFirst first:I usually find it a good idea to call MoveFirstafter opening a
Recordsetto ensure that I have a valid record ready for processing.
Sub M oveLast( )
The MoveLastmetho d mo ves the c urrent rec o rd po inter to the last rec o rd in the
Recordset. No te that yo u c an’t use the MoveLastmetho d with a fo rward-o nly c urso r.
Sub M oveNext ( )
The MoveNextmetho d mo ves the c urrent rec o rd po inter to the next rec o rd in the
Recordset. If the c urrent rec o rd po inter is at the last rec o rd in the Recordset, the c urrent rec o rd po inter will be mo ved to EOF. If the c urrent rec o rd po inter is already at EOF, a c all to MoveNextwill c ause a runtime erro r.
Sub M ovePrevious ( )
The MovePreviousmetho d mo ves the c urrent rec o rd po inter to the previo us rec o rd in the Recordset. If the c urrent rec o rd po inter is o n the first rec o rd in the
Recordset, the c urrent rec o rd po inter will be mo ved to BOF. If the c urrent rec o rd po inter is already at BOF, a c all to MovePreviouswill trigger a runtime erro r.
Function NextRecordset ([RecordsAffected]) As Recordset
The NextRecordsetmetho d c lears the c urrent Recordseto bjec t and returns the next Recordsetthat resulted fro m a query o r sto red pro c edure that returned multi-ple Recordsets. RowsAffectedis a Longvalue c o ntaining the number o f rec o rds affec ted.
Sub Open ([Source As Variant], [ActiveConnection As Variant],
[CursorType As CursorTypeEnum = adOpenUnspecified], [LockType As
LockTypeEnum], [Options As Long = -1])
The Openmetho d o pens a new Recordseto bjec t.
Sourceis a Variantc o ntaining an o bjec t referenc e to a valid Commando bjec t; an o bjec t referenc e o f a valid Streamo bjec t c o ntaining a persistently sto red Recordset; o r a Stringc o ntaining a SQL statement, a table name, the name o f a sto red pro c e-dure, a URL, o r the name o f a file.
ActiveConnectionis a Variantthat c o ntains an o bjec t referenc e to an o pen
Connectiono bjec t o r a Stringvalue that c o ntains the same c o nnec tio n info rma-tio n fo und in the ConnectionStringpro perty.
CursorTypeis an enumerated value ( see Table 14-11) that spec ifies the type o f c ur-so r that will be used o n the Recordset.
LockTypeis an enumerated value ( see Table 14-12) c o ntaining the lo c king mo de used by the Recordsetwhen retrieving rec o rds.
Optionso ptio nally passes o ne o f the values spec ified in Table 14-3.
Table 14-11
Values for CursorType
Constant Value Description
adOpenUnspecified -1 The type of cursor isn’t specified.
adOpenForwardOnly 0 A forw ard-only cursor is used, w hich perm its you only to scroll forw ard through the records in the Recordset.
adOpenKeyset 1 A keyset cursor is used, w hich is sim ilar to a dynam ic cursor, but doesn’t perm it you to see records added by other users.
adOpenDynamic 2 A dynam ic cursor is used, w hich allow s you to see records added by other users, plus any changes and deletions m ade by other users.
adOpenStatic 3 A static cursor is used, w hich prevents you from seeing any and all changes from other users.
Table 14-12
Values for LockType
Constant Value Description
adLockUnspecified -1 The type of locking isn’t specified.
adLockReadOnly 1 Doesn’t perm it you to change any values.
Constant Value Description
adLockOptimistic 3 Records are locked only w hen you call the
UpdateMethod.
adLockBatchOptimistic 4 Records are not locked, and conflicts w ill be returned for resolution after the
UpdateBatchm ethod has com pleted.
Sub Requery ([Options As Long = -1])
The Requerymetho d gets a fresh c o py o f the data in a Recordsetby re-exec uting the query that o riginally generated the Recordset.
Optionsis a Longvalue that desc ribes ho w to exec ute the query. Yo u may set its value to any c o mbinatio n o f the fo llo wing values desc ribed in Table 14-13: adAsync Execute, adAsyncFetch, adAsynchFetchNonBlocking, and adExecuteNoRecords. If o mitted, no ne o f these values will be selec ted.
Table 14-13
Values for Options
Constant Value Description
adOptionUnspecified -1 No options are specified.
adCmdText 1 CommandTextcontains either a SQL
statem ent or a stored procedure call.
adCmdTable 2 CommandTextcontains the nam e of a
table in the database.
adCmdStoredProcedure 4 CommandTextcontains the nam e of a stored procedure.
adCmdUnknown 8 The type of com m and isn’t know n.
adAsyncExecute 16 The com m and should be executed asynchronously.
adAsyncFetch 32 After the num ber of row s specified in the
CacheSizeproperty of the Recordset
object are returned, the rem aining row s w ill be returned asynchronously.
Table 14-13
(continued)
Constant Value Description
adAsyncFetchNonBlocking 64 The m ain thread isn’t blocked w hile retrieving row s. If the current row hasn’t been retrieved, the current row w ill be m oved to the end of the file.
adExecuteNoRecords 128 Indicates that the com m and w ill not return any row s or w ill autom atically discard any row s that are generated. Must be used w ith either the adCmdTextor
adCmdStoredProcedurevalues.
adCmdFile 256 CommandTextis the nam e of a persistently stored Recordset.
adCmdTableDirect 512 CommandTextcontains the nam e of a database table.
Sub Resync ([AffectRecords As AffectEnum],
[ResyncValues As ResyncEnum)
The Resyncmetho d gets any updates to the data that may have happened while using a static o r fo rward-o nly c urso r. Unlike the Requerymetho d, the Resync
metho d do es no t re-exec ute the query asso c iated with the Recordset, so any ro ws added sinc e the o riginal query was exec uted will no t be visible.
AffectRecordsis an enumerated type that desc ribes whic h rec o rds will be affec ted by the c anc el o peratio n ( see Table 14-9) .
ResyncValuesis an enumerated type that determines ho w c hanged rec o rds in the
Recordsetwill b e handled. A value o f adResyncUnderlyingValues( 1) means that all pending updates are saved, while a value o f adResyncAllValues( 2) means that all pending updates are c anc eled ( default) .
Sub Save ([Destination], [PersistFormat As PersistFormatEnum])
Destinationis a Variantvalue c o ntaining either an o bjec t referenc e to a Stream
o r a Stringc o ntaining the fully qualified filename where the data will be sto red.
PersistFormatis an enumerated data type who se value is either adPersistADTG
( 0) , whic h will save the Recordsetin the Advanc ed Data TableGram ( ADTG) fo rmat ( default) , o r adPersistXML( 1) , whic h will save the Recordsetusing XML fo rmat.
Sub Seek (KeyValues, [SeekOption As SeekEnum])
The Seekmetho d is used to mo ve the c urso r to a new lo c atio n in the Recordset. It wo rks with the Indexpro perty to searc h the spec ified index fo r a partic ular value.
KeyValuesis an array o f Variantvalues, c o rrespo nding to the c o lumns in the index.
SeekOptionis an enumerated data type that spec ifies ho w to perfo rm the c o mpari-so n ( see Table 14-14) .
Table 14-14
Values for SeekOption
Constant Value Description
adSeekFirstEQ 1 Seeks the first row w ith a key value equal to
KeyValues.
adSeekLastEQ 2 Seeks the last row w ith a key value equal to
KeyValues.
adSeekAfterEQ 4 Seeks the first row w ith a key value greater than or equal to KeyValues.
adSeekAfter 8 Seeks the first row w ith a key value greater than
KeyValues.
adSeekBeforeEQ 16 Seeks the first row w ith a key value just less than or equal to KeyValues.
adSeekBefore 32 Seeks the first row w ith a key value just less than
KeyValues.
Clients not wanted: The Seekm ethod w ill not w ork w ith client-side cursors (dis-cussed later in this chapter), so select adUseServerfor the CursorType prop-erty.
Function Supports (CursorOptions As CursorOptionEnum) As Boolean
The Supportsmetho d returns TRUEif the data pro vider suppo rts the c o mbinatio n o f values spec ified in CursorOptions. CursorOptionsis a Longvalue who se value is c reated by adding o ne o r mo re values o f the values listed in Table 14-15 to gether.
Table 14-15
Values for CursorOptions
Constant Value Description
adHoldRecords 256 The provider w ill retrieve m ore records or changes to another position w ithout com m itting all pending changes.
adMovePrevious 512 The provider supports the MoveFirst,
MovePrevious, Move, and GetRowsm ethods to m ove the cursor backw ards w ithout requiring bookm arks.
adBookmark 8192 The provider supports the Bookmarkproperty.
adApproxPosition 16384 The provider supports the AbsolutePosition
and AbsolutePageproperties.
adUpdateBatch 65536 The provider supports the UpdateBatchand
Cancelbatch m ethods.
adResync 131072 The provider supports the Resyncm ethod.
adNotify 262144 The provider supports notifications, w hich im plies that Recordsetevents are supported.
adFind 524288 The provider supports the Findm ethod.
adSeek 4194304 The provider supports the Seekm ethod.
adIndex 8388608 The provider supports the Indexproperty.
adAddNew 16778240 The provider supports the AddNewm ethod.
adDelete 16779264 The provider supports the Deleteposition.
adUpdate 16779984 The provider supports the Updatem ethod.
Sub Update ([Fields], [Values])
The Updatemetho d saves any c hanges yo u make the c urrent ro w o f a Recordset. Yo u c an either update the ro w direc tly by ac c essing eac h field by using the
If yo u mo ve to ano ther ro w in the Recordset, ADO will auto matic ally c all the
Updatemetho d to save yo ur c hanges. Yo u must explic itly c all the CancelUpdate
metho d to disc ard any c hanges yo u may have made befo re mo ving to ano ther ro w.
Fieldsis a Variantvalue c o ntaining a single field name o r a Variantarray c o n-taining a list o f field names.
Valuesis a Variantvalue c o ntaining a single value o r a Variantarray c o ntaining a list o f values, who se po sitio n in the array c o rrespo nd to the field names in the
Fieldsparameter.
All or none: You m ust specify both the Fieldsand Valuesparam eters or nei-ther. Specifying only one w ill cause an error. Also if you pass an array for Fields, the Valuesproperty m ust also be an array of an identical size.
Sub UpdateBatch ([AffectRecords As AffectEnum])
The UpdateBatchmetho d saves all pending batc h c hanges to the database.
AffectRecordsis an enumerated data type indic ating whic h ro ws in the
Recordsetwill be affec ted ( see Table 14-9) .
It sort of worked: You m ust check the Errors collection after perform ing a
UpdateBatchto determ ine w hich row s w eren’t properly updated. You can set the Filter property to adFilterAffectedRecords and m ove though the rem aining records to identify those w ith problem s by checking the Status
property.
Recordset object events
The Recordseto bjec t c o ntains many different events to handle vario us c o nditio ns enc o untered in the Recordset.
Event EndOfRecordset (fM oreData As Boolean, adStatus As
EventStatusEnum, pRecordset As Recordset)
The EndOfRecordsetevent is triggered when the pro gram attempts to mo ve beyo nd the end o f the Recordset. This is mo st likely triggered by a c all to MoveNext. Yo u c an use this event to ac quire mo re ro ws fro m the database and append them to the end o f Recordsetto allo w the MoveNextto suc c eed. If yo u do this, yo u must set the
fMoreDataparameter to TRUEto indic ate that the c urso r is no lo nger at the end o f the Recordset.
fMoreDatais a Booleanvalue where TRUEmeans that mo re ro ws have been added to the Recordset.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) . When the event is triggered, this value will be set to either adStatusOko r adStatusCantDeny. If it is set to
adStatusCantDeny, yo u c an’t set the parameter to adStatusCancel.
Table 14-16
Values for EventStatusEnum
Constant Value Description
AdStatusOK 1 The operation that triggered the event w as successful.
adStatusErrorsOccured 2 The operation that triggered the event failed.
adStatusCantDeny 3 The operation can’t be canceled.
adStatusCancel 4 Requests that the operation that triggered the event be canceled.
adStatusUnwantedEvent 5 Prevents subsequent notifications before the event m ethod has finished executing.
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Event FetchComplete (pError As Error, adStatus As EventStatusEnum,
pRecordset As Recordset)
The FetchCompleteevent is triggered after all o f the ro ws have been retrieved dur-ing an async hro no us o peratio n.
pErroris an o bjec t referenc e to an Erroro bjec t c o ntaining any erro r info rmatio n. This pro perty is o nly valid if adStatusis set to adStatusErrorsOccured.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) . Yo u may also set this value to
adStatusUnwantedEventbefo re the event c o mpletes to prevent it fro m being c alled again.
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Event FetchProgress (Progress As Long, M axProgress As Long,
adStatus As EventStatusEnum, pRecordset As Recordset)
Progressis a Longvalue indic ating the number o f rec o rds that have been retrieved so far.
MaxProgressis a Longvalue indic ating the number o f rec o rds that are expec ted to be retrieved.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Event FieldChangeComplete (cFields As Long, Fields, pError asError,
adStatus As EventStatusEnum, pRecordset As Recordset)
The FieldChangeCompleteevent is c alled after the values o f o ne o r mo re Field
o bjec ts have been c hanged. This c an happen if the pro gram assigns a value to the
Valuepro perty o f the Fieldo bjec t o r by using the Updatemetho d and spec ifying a list o f fields and values.
cFieldsis a Longvalue indic ating the number o f fields in Fields.
Fieldsis an array o f o bjec t po inters that po int to Fieldo bjec ts that were c hanged.
pErroris an Erroro bjec t c o ntaining any erro r that may have o c c urred. This value is valid o nly if adStatusis set to adStatusErrorsOccured.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Event M oveComplete (adReason As EventReasonEnum, pError As Error,
adStatus As EventStatusEnum, pRecordset as Recordset)
The MoveCompleteevent is c alled after the c urrent rec o rd has c hanged to a new po sitio n in the Recordset.
Counting rows: If you w ant to display the relative position of the cursor in the
Recordset, the MoveCompleteevent is an ideal place for this. You can easily use the AbsolutePositionproperty to display the current record num ber and the RecordCountproperties to display the total num ber of records retrieved.
adReasonis an enumerated data type indic ating the o peratio n that o riginally c aused the mo ve ( see Table 14-17) .
Table 14-17
Values for EventReasonEnum
Constant Value Description
adRsnAddNew 1 The operation executed an AddNewm ethod.
adRsnDelete 2 The operation used the Deletem ethod.
adRsnUpdate 3 The operation perform ed an Updatem ethod.
adRsnUndoUpdate 4 The operation reversed an Updatem ethod.
adRsnUndoAddNew 5 The operation reversed an AddNewm ethod.
adRsnUndoDelete 6 The operation reversed a Deletem ethod.
adRsnRequery 7 The operation perform ed a Requery.
adRsnResync 8 The operation perform ed a Resync.
adRsnClose 9 The operation closed the Recordset.
adRsnMove 10 The operation m oved the current record pointer to a different record.
adRsnFirstChange 11 The operation m ade the first change to a row.
adRsnMoveFirst 12 The operation m oved the current record pointer to the first record in the Recordset.
adRsnMoveNext 13 The operation m oved the current record pointer to the next record in the Recordset.
adRsnMovePrevious 14 The operation m oved the current record pointer to the previous record in the Recordset.
adRsnMoveLast 15 The operation m oved the current record pointer to the last record in the Recordset.
pErroris an Erroro bjec t c o ntaining any erro r that may have o c c urred. This value is o nly valid if adStatusis set to adStatusErrorsOccured.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
Event RecordChangeComplete (adReason As EventReasonEnum,
cRecords As Long, pError As Error, adStatus As EventStatusEnum,
pRecordset as Recordset)
The RecordChangeCompleteevent is c alled after o ne o r mo re rec o rds in the
Recordsethave been c hanged.
adReasonis an enumerated data type indic ating the o peratio n that o riginally c aused the c hange ( see Tab le 14-17) . Po ssib le values are the fo llo wing:
adRsnAddNew, adRsnDelete, adRsnUpdate, adRsnUndoUpdate,
adRsnUndoAddNew, adRsnUndoDelete, and adRsnFirstChange.
cRecordsis a Longvalue c o ntaining the number o f rec o rds that were c hanged.
pErroris an Erroro bjec t c o ntaining any erro r that may have o c c urred. This value is o nly valid if adStatusis set to adStatusErrorsOccured.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Event RecordsetChangeComplete (adReason As EventReasonEnum,
pError As Error, adStatus As EventStatusEnum, pRecordset as
Recordset)
The RecordsetChangeCompleteevent is c alled after a c hange to the Recordset.
adReasonis an enumerated data type indic ating the o peratio n that o riginally c aused the mo ve ( see Table 14-17) . Po ssible values are the fo llo wing: adRsnClose,
adRsnReQuery, and adRsnReSync.
pErroris an Erroro bjec t c o ntaining any erro r that may have o c c urred. This value is o nly valid if adStatusis set to adStatusErrorsOccured.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
Event WillChangeField (cFields As Long, Fields, adStatus As
EventStatusEnum, pRecordset As Recordset)
The WillChangeFieldevent is c alled befo re an o peratio n that will c hange the val-ues in o ne o r mo re Fieldo bjec ts is started. After the c hanges have been made, the
FieldChangeCompleteevent is fired. Yo u c an c ho o se to c anc el the o peratio n by setting the adStatuspro perty to adStatusCancel.
cFieldsis a Longvalue indic ating the number o f fields in Fields.
Fieldsis an array o f o bjec t po inters that po int to Fieldo bjec ts that are to be c hanged.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Event WillChangeRecord (adReason As EventReasonEnum, cRecords As
Long, pError As Error, adStatus As EventStatusEnum, pRecordset as
Recordset)
The WillChangeRecordevent is c alled befo re o ne o r mo re rec o rds in the
Recordsetwill be c hanged.
adReasonis an enumerated data type indic ating the o peratio n that c aused the c hange ( see Table 14-17) . Po ssible values are the fo llo wing: adRsnAddNew,
adRsnDelete, adRsnUpdate, adRsnUndoUpdate, adRsnUndoAddNew,
adRsnUndoDelete, and adRsnFirstChange.
cRecordsis a Longvalue c o ntaining the number o f rec o rds will be c hanged.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Event WillChangeRecordset (adReason As EventReasonEnum, pError As
Error, adStatus As EventStatusEnum, pRecordset as Recordset)
The WillChangeRecordsetevent is c alled befo re the Recordsetis c hanged.
adReasonis an enumerated data type indic ating the o peratio n that c aused the c hange ( see Table 14-17) . Po ssible values are the fo llo wing: adRsnClose,
pErroris an Erroro bjec t c o ntaining any erro r that may have o c c urred. This value is o nly valid if adStatusis set to adStatusErrorsOccured.
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Event WillM ove (adReason As EventReasonEnum, adStatus As
EventStatusEnum, pRecordset as Recordset)
The WillMoveevent is c alled befo re the c urrent rec o rd po inter is c hanged to a new po sitio n in the Recordset.
adReasonis an enumerated data type indic ating the o peratio n that o riginally c aused the mo ve ( see Table 14-16) .
adStatusis an enumerated value that indic ates the ac tio n that sho uld be taken when the event returns ( see Table 14-16) .
pRecordsetis an o bjec t referenc e to the Recordsetthat triggered the event.
Before Opening a Recordset
Befo re yo u o pen a rec o rdset there are a number o f issues yo u need to c o nsider. Fo r instanc e, yo u need to dec ide whether o r no t yo u plan to update the database. Then yo u need to dec ide what type o f c urso r yo u want to use. Finally, yo u need to dec ide where the c urso r sho uld be lo c ated. These issues have a big impac t o n ho w yo ur applic atio n perfo rms, no t o nly fo r a single user, but fo r all o f the users that ac c ess yo ur database server.
Locking considerations
yo ur ac c o unt and begin to pro c ess the withdrawal. Then the depo sit pro gram reads the c urrent balanc e and updates the database with the new balanc e. Finally, the withdrawal pro gram po sts the balanc e it c o mputes. This is a serio us pro blem ( altho ugh I wish it wo rked the o ther way) .
Figure 14-1: Processing concurrent database updates w ithout locks
To avo id this pro blem, yo u need to prevent all o ther users fro m ac c essing this partic -ular ac c o unt until after the update has been c o mpleted. Figure 14-2 sho ws ho w the same sequenc e o f ac tio ns wo uld wo rk with lo c ks. The withdrawal pro gram is able to read the ac c o unt balanc e immediately, and it plac es a lo c k o n the ac c o unt so no o ther pro grams c an ac c ess the info rmatio n. When the depo sit pro gram attempts to read the balanc e, it is fo rc ed to wait fo r the lo c k to be released. This allo ws the with-drawal pro gram to finish its pro c essing uninterrupted and release the lo c k it plac ed o n the ac c o unt. Onc e the lo c k is released, the ac c o unt balanc e will be returned to the depo sit pro gram, whic h c an then c o mplete its updates ac c urately.
Figure 14-2: Processing concurrent database updates w ith locks
With-As yo u c an see, lo c king is nec essary to ensure that c hanges to the database are applied in the c o rrec t o rder. In mo st c ases, the o rder o f the c hanges against the database isn’t impo rtant as lo ng as the c hanges are made sequentially rather than c o nc urrently. After all, it do esn’t matter whether the depo sit is made first o r the withdrawal is made first as lo ng as they aren’t made at the same time.
The ADO LockTypeallo ws yo u to c ho o se fro m o ne o f fo ur different types o f lo c ks: read-o nly, pessimistic , o ptimistic , and batc h o ptimistic . Yo u need to c ho o se the o ne that best suits yo ur needs.
Read-only locks
While lo c ks are nec essary when perfo rming updates, it is useful to tell the database server that yo u are never go ing to update the data in the database. In a sense, a re ad-o nly lo ckis no t a lo c k at all, but spec ifying a read-o nly lo c k ensures that yo u c an’t update the database.
Pessimistic locks
A pe ssimistic lo ckis the mo st c o nservative lo c k available in ADO. When yo u begin to edit a rec o rd by assigning a new value into o ne o f the existing fields in the ro w, a lo c k is plac ed o n the ro w so that no o ther users c an ac c ess it. The ro w remains lo c ked until yo u update it using the Updatemetho d.
One pro blem with using pessimistic lo c king is that in additio n to the ro w yo u are mo difying, all o f the ro ws sto red in the same physic al blo c k o f sto rage ( typic ally c alled a database page) are also lo c ked, whic h makes them unavailable fo r o ther users also .
In days of old: The current version of m ost popular database system s supports row -level locking, w hich m eans that a lock affects only the row that it w as intended for and not the other row s in the sam e physical block of storage.
Ho wever, a bigger pro blem with pessimistic lo c king is that the lo c k is held during the entire time yo u are editing the ro w. Depending o n ho w yo ur applic atio n wo rks, the lo c k c o uld be held anywhere fro m a few mo ments to many minutes. In so me applic atio ns this may no t be c ritic al, but in o thers it c o uld c ause serio us pro blems bec ause o ther applic atio ns may be fo rc ed to wait until yo u c o mplete the edit. Also the database server may take the lo c k away fro m yo u if yo u held it to o lo ng, whic h will c ause an erro r when yo u eventually get aro und to finishing the update. In general, the mo re ro ws yo u have in a table, the fewer pro blems yo u will have with c o nflic ting pessimistic lo c ks. Likewise, perfo rming fewer updates and having fewer users also reduc es the likeliho o d o f a lo c k c o nflic t.
Optimistic locks
Optimistic lo cksstill ensure that yo ur update is perfo rmed c o rrec tly. Unlike pes-simistic lo c ks, ho wever, o ptimistic lo c ks aren’t plac ed until yo u c all the Update
metho d, so a lo c k is no t plac ed o n the ro w when yo u begin editing the ro w. When the update is perfo rmed, the ro w is lo c ked, and the c urrent value o f eac h field in the database server is c o mpared to the o riginal value o f eac h field taken when the applic atio n pro gram retrieved the ro w. If there aren’t any differenc es, the update will pro c eed no rmally. Otherwise an erro r will be returned to yo ur pro gram. It will be up to yo ur pro gram to dec ide whether to reapply the c hanges o r restart the update fro m the beginning.
Batch optimistic locks
Batch o ptimisticlo c ks are similar to o ptimistic lo c ks, exc ept yo u c an update multi-ple ro ws b efo re returning them to the datab ase server fo r updating using the
UpdateBatchmetho d. After perfo rming a b atc h update, yo u need to review eac h o f the ro ws yo u updated to ensure that the c hanges were applied to the datab ase. This type o f lo c k is useful when yo u want to add lo ts o f ro ws to a table. It is impo s-sible fo r anyo ne to update any o f the values in these ro ws, sinc e the data hasn’t been sent to the database yet.
Choosing a cursor type
While lo c ks affec t ho w yo u update data, c urso r types affec t ho w yo ur applic atio n will see c hanges in the datab ase that are made b y o ther users. Cho o sing the appro -priate c urso r type is impo rtant and depends mo stly o n ho w yo u plan to use the data. ADO suppo rts fo ur types o f c urso rs: fo rward-o nly c urso rs, static c urso rs, keyset c urso rs, and dynamic c urso rs.
Forward-only cursors
A fo rward-o nly curso ris the mo st restric tive o f all o f the c urso rs available. It is avail-able o nly in c o mbinatio n with a read-o nly lo c k. It presents a static view o f the data in the Recordsetthat c an’t be addressed rando mly. Any c hanges, additio ns, o r deletio ns to the underlying data will no t be visible to yo ur pro gram.
Yo u must sc ro ll thro ugh the Recordseto ne ro w at a time fro m the beginning to the end. If yo u need to mo ve bac kwards o r start o ver again, yo u will have to c lo se the
Recordsetand reo pen it.
Static cursors
Like the fo rward-o nly c urso r, a static curso ralso pro vides a static view o f yo ur data. Rec o rds that have been added, deleted, o r updated will no t be visible to yo ur pro -gram. Ho wever, yo u may mo ve the c urrent rec o rd po inter to any lo c atio n in the
Recordsetwitho ut restric tio n.
Client-side only: A static cursor is your only choice for client-side cursors, though it m ay be used w ith a server-side cursor as w ell.
Keyset cursors
A ke yse t curso rallo ws yo u to see any updates o r deletio ns, but no t additio ns made to the underlying data that have been made after yo u o pened the Recordset. Bo o kmarks are suppo rted, and yo u may mo ve anywhere in the Recordsetyo u c ho o se.
Keyset c urso rs wo rk by keeping a list o f bo o kmarks in a tempo rary table o n the server. As yo u mo ve fro m o ne ro w to ano ther, the pro vider will retrieve the mo st c urrent values asso c iated with the partic ular ro w. In general, I avo id keyset c urso rs bec ause they are slo wer than static c urso rs and do n’t pro vide all o f the updates to the database as do es a dynamic c urso r.
Dynamic cursors
Dynamic curso rsallo w yo u to view any c hanges made to the database, inc luding additio ns, deletio ns, and updates. All fo rms o f mo vement thro ugh the Recordset
that do n’t rely o n Bookmarksare always suppo rted. No te that mo st data pro viders inc lude bo o kmark suppo rt even tho ugh it isn’t required.
Dynamic c urso rs are useful if yo u want to see all o f the c hanges in the underlying data yo u retrieved fro m the datab ase. They are o nly appro priate if yo u are using a server-side c urso r and there is mo re o verhead when using a dynamic c urso r b ec ause the pro vider has to c hec k c o ntinually fo r c hanges in the datab ase. Ho wever, if yo u are o nly retrieving a few ro ws fro m the datab ase, then dynamic c urso rs may b e appro priate.
Picking a cursor location
The last majo r c ho ic e yo u have to make when o pening a rec o rdset is c ho o sing b etween a server-side c urso r and a c lient-side c urso r. This c ho ic e is made using the CursorLocationpro perty.
Server-side cursors
A se rve r-side curso ris the traditio nal c urso r used in a datab ase system. It direc tly ac c esses data o n the server. A req uest to mo ve the c urrent rec o rd po inter to a dif-ferent rec o rd results in a req uest to the datab ase server ( unless, o f c o urse, yo u set CacheSizeto a value greater than o ne, and the rec o rd is in the lo c al c ac he) . Server-side c urso rs c an b e used with keyset and dynamic c urso rs to allo w yo ur pro gram to see c hanges in the live datab ase.
Client-side cursors
A clie nt-side curso ris a spec ial type o f c urso r that allo ws yo u a ric her enviro nment with whic h to build yo ur applic atio n than a server-side c urso r do es. Data is buffered lo c ally, and yo u c an o perate in disc o nnec ted mo de fro m the database server. After retrieving yo ur data fro m the database, yo u c an break the c o nnec tio n and wo rk with the info rmatio n in the rec o rdset lo c ally. Later yo u c an rec o nnec t and apply whatever c hanges yo u made lo c ally to the database server.
I can’t see it: The UnderlyingValueproperty is not available on Field
objects using a client-side cursor, since all of the records are buffered locally.
Opening a Recordset
There are three main ways to c reate a Recordset. As yo u saw in Chapter 13, yo u c an c reate a Commando b jec t and use the Executemetho d to return a referenc e to a Recordseto b jec t. A sec o nd way to c reate a Recordsetis b y sto ring a SQL state-ment, sto red pro c edure name, o r tab le name in the rec o rdset’s Sourcepro perty and then using the Openmetho d to po pulate the rec o rdset. The last way is to set the Sourcepro perty to an ac tive Commando b jec t and then use the Openmetho d. Bec ause I already c o vered the first way in Chapter 13, I’ll c o ver the last two ways here.
Using Source strings
Fo r many applic atio ns all yo u need to use is a Connectiono bjec t and a Recordset
o bjec t. Listing 14-1 is similar to the pro gram in Chapters 13 and uses the same
Connectiono bjec t fro m Chapter 12. Instead o f c reating a Commando bjec t with the
Se le ctstatement, I assign the Se le ctstatement to the Sourcepro perty o f the
Recordset.
Errorsc o llec tio n, I issue the Openmetho d. If there’s a pro blem, I write the erro r message using the WriteErrorro utine fro m Chapter 12. Otherwise, I display the first value fro m the first c o lumn o f the rec o rdset in the status bar just like I did in the previo us versio n o f the pro gram.
Listing 14-1:
The Command7_Click event in Recordset Demo
Private Sub Command7_Click()
Dim rs As ADODB.Recordset
On Error Resume Next
Set rs = New ADODB.Recordset Set rs.ActiveConnection = db
rs.Source = “Select Count(*) From Customers Where State = ‘MD’” rs.CursorLocation = adUseServer
rs.CursorType = adOpenForwardOnly rs.LockType = adLockReadOnly
db.Errors.Clear rs.Open
If db.Errors.Count > 0 Then WriteError
Else
StatusBar1.SimpleText = “Response: “ & _ FormatNumber(rs.Fields(0).Value, 0)
End If
End Sub
Using Command objects
Listing 14-2:
The Command8_Click event in Recordset Demo
Private Sub Command8_Click()
Dim c As ADODB.Command Dim p As ADODB.Parameter Dim rs As ADODB.Recordset
On Error Resume Next
Set c = New ADODB.Command Set c.ActiveConnection = db c.CommandText = “CountByState” c.CommandType = adCmdStoredProc
c.Parameters.Refresh
c.Parameters(“@State”).Value = Text5.Text
Set rs = New ADODB.Recordset Set rs.Source = c
rs.CursorLocation = adUseServer rs.CursorType = adOpenForwardOnly rs.LockType = adLockReadOnly
db.Errors.Clear rs.Open
If db.Errors.Count > 0 Then WriteError
Else
StatusBar1.SimpleText = “Response: “ & _ FormatNumber(rs.Fields(0).Value, 0)
End If
End Sub
Thoughts on Opening a Recordset Object
Summary
In this c hapter yo u learned the fo llo wing:
✦Yo u c an use a server-side c urso r when yo u want to manipulate the rec o rdset o n the database server.
✦Yo u c an use a c lient-side c urso r when yo u want to manipulate the rec o rdset o n the database c lient.
✦Yo u c an use read-o nly lo c ks to prevent o thers fro m c hanging the data while yo ur rec o rdset is o pen.
✦Yo u c an use pessimistic lo c ks to prevent o thers fro m c hanging the values in the c urrent rec o rd in yo ur rec o rdset. This tec hnique ho wever inc urs a signifi-c ant amo unt o f o verhead in the database server.
✦Yo u c an use o ptimistic lo c king when yo u do n’t expec t o thers to c hange the data in the c urrent ro w while yo u are editing it. Of c o urse yo u have to handle the erro r c o nditio n that may arise if so meo ne do es c hange the data while yo u are ac c essing it.
✦Yo u c an use batc h o ptimistic lo c king when making c hanges in a gro up o f rec o rds. This appro ac h has the least o verhead o f all o f the lo c king metho ds, but requires yo u to verify eac h ro w yo u c hanged to insure that the data wasn’t c hanged by ano ther database c lient befo re yo u made yo ur c hanges.