Copyright ©1995 by NeXT Computer, Inc.  All Rights Reserved.

DBRecordList



Inherits From: DBRecordStream : Object
Conforms To: DBContainers
DBCursorPositioning
Declared In: dbkit/DBRecordList.h



Class Description

The DBRecordList class supports buffered access to records in a database.  A DBRecordList object fetches groups of records from a database and presents them as an array that can be accessed using the methods declared in the DBCursorPositioning protocol.  A DBRecordList object permits modifications, deletions, and insertions to the individual records which can then be saved to the database as a group.  This batch approach to record operations distinguishes DBRecordList from its superclass, DBRecordStream.   Note, however, that this increased functionality comes at the cost of increased memory usage.



Setting Up a DBRecordList

You prepare a DBRecordList to fetch records in the same way you would a DBRecordStream.  (See the DBRecordStream class specification for details.)  Additionally, using the setRetrieveMode: method, you can specify whether the fetch will be done synchronously or asynchronously.  By default, a DBRecordList retrieves records synchronously, meaning that it won't respond to further messages until it retrieves all records selected by a given query.  If you specify the asynchronous mode, the DBRecordList creates a separate Mach thread to fetch the records.  The DBRecordList itself is immediately ready to respond to further messages.  As the separate thread fetches records, it passes them back to the DBRecordList, which adds them to its list.

There are actually two asynchronous modes, identified by the constants DB_BackgroundStrategy and DB_BackgroundNoBlockingStrategy.  These modes differ only in the way the DBRecordList behaves when asked to access a record that hasn't yet returned from the database.  For example, if a DBRecordList using the DB_BackgroundStrategy receives a setLast message before all records have been retrieved, the setLast method will block until it can access the last record.  If the DBRecordList were using the DB_BackgroundNoBlockingStrategy, the setLast method would return nil immediately, indicating a failure to access the last record.



Accessing and Modifying Data

All of DBRecordStream's methods for accessing and modifying records (for example, deleteRecord, isModified, and getValue:forProperty:) work with DBRecordList objects.  However, since a DBRecordList can contain multiple records, it also declares methods that take an additional argument, a record index (deleteRecordAt:, isModifiedAt:, and getValue:forProperty:at:).

Methods that access records but don't specify an index act on the record at the present position of the cursor.  The cursor can be reported or set by methods declared in the DBCursorPositioning protocol.

Note:  The internal cursor maintained by a DBRecordList is independent of the DBFetchGroup's current row or current selection (which depend on actions in the user interface).



Saving Changes

As with a DBRecordStream object, a DBRecordList object attempts to save additions, changes, and deletions when it receives a saveModifications message.  If an error occurs during the save operation, the DBRecordList sends its delegate a recordStream:willFailForReason: message (see the DBRecordStream class description for more information).  At the same time, the DBRecordList's cursor is set to point to the row that is failing.  Any rows that fail will be "dirty" after the saveModifications has completed.  This combination of events lets you go back and fix failures, and then resubmit.



Instance Variables

None declared in this class.



Adopted Protocols

DBContainers addObject:forBinder:
count
empty
freeObjects
objectAt:forBinder:
prepareForBinder:
DBCursorPositioning currentPosition
setFirst
setLast
setNext
setPrevious
setTo:



Method Types

Initializing and freeing init
free
clear
Setting the retrieval mode setRetrieveMode:
currentRetrieveMode
Fetching data from the database fetchUsingQualifier:
fetchUsingQualifier:empty:
fetchRecordForRecordKey:
recordLimit
setRecordLimit:
Accessing data getValue:forProperty:
getValue:forProperty:at:
getRecordKeyValue:
getRecordKeyValue:at:
Modifying data setValue:forProperty:
setValue:forProperty:at:
insertRecordAt:
appendRecord
newRecord
isNewRecord
isNewRecordAt:
deleteRecord
deleteRecordAt:
isModified
isModifiedAt:
isModifiedForProperty:at:
Using record indexes positionForRecordKey:
moveRecordAt:to:
swapRecordAt:withRecordAt:
Saving data saveModifications



Instance Methods

appendRecord
appendRecord

Adds an empty record at the end of the record list by invoking DBRecordList's insertRecordAt: method.  Returns the value returned by insertRecordAt:.

See also:  insertRecordAt:, newRecord, deleteRecord, deleteRecordAt:



clear
clear

Resets the DBRecordList.  The DBRecordList's record data, list of properties, and list of key properties are emptied.  Its database instance variable is set to nil, but its delegate remains unchanged.  Its status is set to DB_NotReady.  Returns self.

See also:  empty (DBRecordStream)



currentRetrieveMode
(DBRecordListRetrieveMode)currentRetrieveMode

Returns the DBRecordList's retrieve mode, which can be DB_SynchronousStrategy, DB_BackgroundStrategy, or DB_BackgroundNoBlockingStrategy.  See the class description above for more information.

See also:  setRetrieveMode:



deleteRecord
deleteRecord

Deletes the current record.  Returns nil if there's no current record; otherwise, returns self.

See also:  deleteRecordAt:



deleteRecordAt:
deleteRecordAt:(unsigned)index

Deletes the record at position index.  Returns nil if there's no record at index; otherwise, returns self.

See also:  deleteRecord, currentPosition (DBCursorPositioning)



fetchRecordForRecordKey:
fetchRecordForRecordKey:(DBValue *)aValue

Fetches the record identified by the record key stored in aValue.  Typically, this method is used to find data in DBRecordLists containing related information.  For example, suppose one DBRecordList contains employee data and another contains department data.  The department data for a specific employee can be found by first getting the value of the department number from the employee record (see getRecordKeyValue:at:) and then using it as the argument to fetchRecordForRecordKey: in a message to the DBRecordList containing department information.

Returns nil if no record has the supplied key value or if an error occurs; otherwise, returns self.

See also:  fetchUsingQualifier:, fetchUsingQualifier:empty:



fetchUsingQualifier:
fetchUsingQualifier:(DBQualifier *)aQualifier

Invoking this method is equivalent to invoking  fetchUsingQualifier:empty: with YES as the argument to empty:.  See fetchUsingQualifier:empty:, below.



fetchUsingQualifier:empty:
fetchUsingQualifier:(DBQualifier *)aQualifier empty:emptyFirst

Loads the DBRecordList with records from the database.  Before invoking this method, use setProperties:ofSource: to specify the source and properties of the data to be retrieved.  The scope of the retrieved records is controlled by aQualifier.  For example, assuming the data source is an SQL database, aQualifier could be an object that represents the expression "where name = `Holbein'".  If aQualifier is nil, all records are retrieved.

If emptyFirst is YES, before loading new data, the method first empties the DBRecordList and its list of properties.  Setting emptyFirst to NO leaves records already fetched in the DBRecordList, and append to them the unique records retrieved by the current fetch.  In that case, the effect of successive invocations with different qualifiers builds in the DBRecordList the union of the sets returned by the various qualifiers.

Each fetch can be done synchronously or asynchronously, depending on the fetch mode in effect at the time the fetch is begun (see the class description above for details).  If you specify an invalid fetch mode, fetchUsingQualifier:empty: raises a DB_UNIMPLEMENTED_ERROR exception.

A synchronous fetch is subject to a limit on the total number of records in the DBRecordList, set by setRecordLimit:.  If the number of qualifying records would exceed that limit, the DBRecordList receives that number, and the delegate is sent a recordStream:willFailForReason: message with the argument DB_RecordLimitReached.

Returns nil if the data can't be selected (for example, if the DBDatabase isn't connected to the database) or if the qualifier and DBRecordList refer to different entities in the database; otherwise, returns self.  After fetchUsingQualifier:empty: returns, the DBRecordList's current record is set to the first record in the list.

See also:  cancelFetch, fetchUsingQualifier:, setProperties:ofSource:



free
free

Releases the storage for the DBRecordList.



getRecordKeyValue:
getRecordKeyValue:(DBValue *)aValue

Places the value of the current record's key property (or properties) into aValue.

Returns nil if the DBRecordList has status DB_NotReady or if there is no current record; otherwise, returns aValue.

See also:  getRecordKeyValue:at:



getRecordKeyValue:at:
getRecordKeyValue:(DBValue *)aValue at:(unsigned)index

Places the value of the key property (or properties) for the record at index into aValue.

This method is especially useful when data must be exchanged between DBRecordLists.  For example, suppose one DBRecordList supplies employee information and another supplies department information to the user interface of an application.  A user can change an employee's department by selecting from a list of department names.  After a department name is selected, you can use getRecordKeyValue: to determine the corresponding record's key value so that you can set the department identification in the employee's record.

Returns nil if the DBRecordList has status DB_NotReady or if there is no record at index; otherwise, returns aValue.

See also:  getRecordKeyValue:



getValue:forProperty:
getValue:(DBValue *)aValue forProperty:aProperty

Places the value for the property aProperty of the current record into the DBValue object aValue and returns aValue.

See also:  setValue:forProperty:at:, setValue:forProperty, getValue:forProperty:at:



getValue:forProperty:at:
getValue:(DBValue *)aValue
forProperty:aProperty
at:(unsigned)index

Places the value for the property aProperty of the record at position index into aValue and returns aValueaProperty is an object that conforms to the DBProperties protocol.  Such an object is returned by DBDatabase's propertyNamed: method.  The argument index identifies the record within the DBRecordList and has the range from 0 to the value returned by the count method.

See also:  setValue:forProperty:at:, setValue:forProperty, getValue:forProperty:



init
init

Initializes a newly allocated  DBRecordList.  The DBRecordList's delegate instance variable is set to nil, its retrieve mode is set to DB_SynchronousStrategy, and its cursor (its current record) is set to DB_NoIndex.  Returns self.

This method is the designated initializer for DBRecordList.



insertRecordAt:
insertRecordAt:(unsigned)index

Adds a new, empty record to the record list at index.  The newly inserted record becomes the current record.

Returns nil if the DBRecordList has a DB_NotReady status or if an error prevents the insertion of the record.  Otherwise, returns self.

See also:  appendRecord, deleteRecord, deleteRecordAt:



isModified
(BOOL)isModified

Returns YES if any record in the DBrecordList has been modified, added, or deleted; NO otherwise.

See also:  isModifiedAt:, isModifiedForProperty:at:



isModifiedAt:
(BOOL)isModifiedAt:(unsigned int)index

Returns YES if the record at index is new or has been modified; NO otherwise.

See also:  isModified, isModifiedAt:for:



isModifiedForProperty:at:
(BOOL)isModifiedForProperty:aProperty at:(unsigned int)index

Returns YES if aProperty in the record at index has been modified since the record was added to the DBRecordList or fetched from the database; NO otherwise.

See also:  isModified, isModifiedAt:



isNewRecord
(BOOL)isNewRecord

Returns YES if the current record is new; that is, it the result of the DBRecordList receiving an appendRecord, insertRecordAt:, or newRecord message.

See also:  isNewRecordAt:, isModified



isNewRecordAt:
(BOOL)isNewRecordAt:(unsigned int)index

Returns YES if the record at index is new; that is, if it was produced by the DBRecordList's receiving an appendRecord, insertRecordAt:, or newRecord message.

See also:  isNewRecord, isModified



moveRecordAt:to:
moveRecordAt:(unsigned int)sourceIndex to:(unsigned int)destinationIndex

Moves the record at sourceIndex to destinationIndex.  Returns nil if there is no record at sourceIndex or if an error prevents the insertion of the record are destinationIndex; otherwise, returns self.



newRecord
newRecord

Creates a new, empty record by invoking DBRecordList's insertRecordAt: method and passing the index of the current row as the argument.  Before this operation can take place, the DBRecordList attempts to save modifications of the current record to the database.  If these changes can't be saved, newRecord returns nil, and no new record is created.  Otherwise, newRecord returns self, and the new record becomes the current record.

See also:  saveModifications



positionForRecordKey:
(unsigned int)positionForRecordKey:(DBValue *)aValue

Searches the records in the DBRecordList for the first record whose key value matches aValue.  Returns DB_NoIndex if no such record is found; otherwise, returns the index of the matching record.



recordLimit
(unsigned int)recordLimit

Returns the maximum number of records that a fetch can deliver to a DBRecordList (as set by setRecordLimit:).  If no limit has been set, returns DB_NoIndex.



saveModifications
(unsigned int)saveModifications

Saves to the database any changes (additions, deletions, or modifications) that have been made to the list of records.  If the database supports transactions and there's no transaction in progress, this save operation is nested within a new transaction, called a local transaction.  If there is already a transaction in progress for the RecordList's database, the modification is attempted within that transaction context, without generating a new transaction.

The possible return values from saveModifications are as follows:

Value Reason
0 The save operation was successful.
1 The save completed but not all records were saved.  This happens if errors are encountered but the delegate requests that the save proceed anyway.
DB_NoIndex Either the DBRecordList isn't ready (its status is DB_NotReady or DB_NoRecordKey), or one or more records in the database have changed since they were fetched and the delegate hasn't forced the modifications to be saved.  (See recordStream:willFailForReason: (DBRecordStream))

If a local transaction can't be committed due to errors, a DB_TRANSACTION_ERROR exception is raised.

If the attempt to save modifications fails, the DBRecordList's delegate is notified by sending it a recordStream:willFailForReason: message, and the DBRecordStream's internal cursor is set to the first of the first of the records that should have been saved but weren't.

See also:  areTransactionsEnabled (DBDatabase), beginTransaction (DBDatabase)



setRecordLimit:
setRecordLimit:(unsigned int)count

Makes count the maximum number of records that can be retrieved during a fetch.  If a fetch is attempted with a qualifier that would fetch more than this number of records, the method returns the maximum number permitted but sends a recordStream:willFailForReason: message to the delegate with the argument DB_RecordLimitReached.  Returns self.



setRetrieveMode:
setRetrieveMode:(DBRecordListRetrieveMode)aMode

Sets the DBRecordList's retrieve mode, which can be DB_SynchronousStrategy, DB_BackgroundStrategy, or DB_BackgroundNoBlockingStrategy.  See the class description above for more information.

See also:  currentRetrieveMode:



setValue:forProperty:
setValue:(DBValue *)aValue forProperty:aProperty

Sets the value for aProperty in the current record to that contained in aValue.  Returns a nonzero value if successful; otherwise, returns nil.

See also:  getValue:forProperty:, setValue:forProperty:at:



setValue:forProperty:at:
setValue:(DBValue *)aValue
forProperty:aProperty
at:(unsigned int)index

Sets the value for aProperty in the record at index to that contained in aValue.  Returns a nonzero value if successful; otherwise, returns nil.

See also:  getValue:forProperty:, setValue:forProperty



swapRecordAt:withRecordAt:
swapRecordAt:(unsigned int)anIndex withRecordAt:(unsigned int)anotherIndex

Transposes the locations of two records.  Both arguments must be valid positions in the DBRecordList's sequence of records. Returns self, but if an argument is invalid, returns nil.