• Keine Ergebnisse gefunden

Class Description

Im Dokument Oriented Software (Seite 27-36)

A DBAssociation object is the link between a property in a DBRecordList and a user interface object-called the destination-that displays and lets the user manipulate values for that property. DBAssociation objects are created and owned by DBFetchGroup objects;

a DBFetchGroup automatically creates and configures a DBAssociation for each interface object that it (the DBFetchGroup) manages, so that you never need to create DB Association objects directly. In addition, you should rarely need to create a subclass of DBAssociation.

(However, if you create your own user interface class to display database values, that class will need to implement some of the DBCustomAssociation category methods.)

You retrieve DBAssociationobjects through DBModule's associationForObject: method (DBModules manage DBFetchGroups), as explained in the specification for the

DBModule class. Once you've gotten a DBAssociation, you should only send it querying messages; you never alter a DB Association directly.

Instance Variables

None declared in this class.

Method Types

Initializing

Querying the object

4-20 Chapter 4: Database Kit

- initFetchGroup:expression:destination:

- destination - fetch Group

~ expression

Manipulating the object

Instance Methods

contentsDidChange - contentsDidChange

- contentsDidChange - setDestination:

- currentRecordDidDelete - endEditing

- selectedRow After:

- selectionDidChange - validateEditing - getValue:

- setValue:

Notifies the DBAssociation that the destination's contents have changed. You never invoke this method directly; it's invoked automatically by an internal mechanism.

currentRecordDidDelete - currentRecordDidDelete

Notifies the DBAssociation that the current record (in the associated DBRecordList) has been deleted. You never invoke this method directly; it's invoked automatically by an internal mechanism.

destination - destination

Returns the user interface object that's associated with this DBAssociation.

endEditing - endEditing

Tells the DBAssociation to disallow further editing in the user interface object. You never invoke this method directly; it's invoked automatically by an internal mechanism.

expression - expression

Returns the DBExpression that represents the property associated with this DBAssociation.

fetchGroup - fetchGroup

Returns the DBFetchGroup that owns this DB Association.

getValue:

- getValue:value

Instructs the DB Association to copy the value from its destination into value. You never invoke this method directly; it's invoked automatically by an internal mechanism.

initFetchGroup:expression:destination:

- initFetchGroup:aFetchGroup expression:anExpr destination:aDest

Initializes an instance of DBAssociation such that anExpr, a DBExpression object that represents a property in a DBRecordList, is associated with the destination aDest. The DBAssociation will be owned by aFetchGroup. You never invoke this method directly; it's invoked automatically by the owning DBFetchGroup object.

setDestination:

- setDestination:new Destination

Sets the DBAssociation's destination. You should rarely need to invoke this method directly. Returns self.

selectedRow After:

- (unsigned int)selectedRowAfter:(unsigned int)previousRow

Returns the index of a row in the DBAssociation's destination to which this association is linked. You never invoke this method directly; it's invoked automatically by an internal mechanism.

4-22 Chap'ter 4: Database Kit

selectionDidChange - selectionDidChange

Notifies the DB Association that there has been some sort of change in the current row of the DBFetchGroup. You never invoke this method directly; it's invoked automatically by an internal mechanism.

setValue:

- setValue:value

Sets a value in the DBAssociation's DBRecordList. You never invoke this method directly;

it's invoked automatically by an internal mechanism.

validateEditing - validateEditing

Invokes validation for the DBAssociation's destination after editing. You never invoke this method directly; it's invoked automatically by an internal mechanism.

DBBinder

Inherits From: Object

Conforms To: D BCursorPositioning Declared In: dbkitIDBBinder.h

Class Description

The DBBinder class provides a mechanism for connecting individual data items in a database to particular objects, variables, and methods in your application. Most

applications benefit by avoiding DBBinders and working instead with higher-level classes such as DBRecordList or DB RecordStream. You should create and use DBBinder objects only if your application needs to augment or modify the functionality provided by DBRecordStream or DBRecordList.

Preparing a DBBinder

To access a database, a DBBinder must be initialized and associated with a database model through a DBDatabase object, as shown below:

/* Initialize the DBBinder through the init method. */

DBBinder *myBinder = [[DBBinder alloc] init] i

/* Associate it with a DBDatabase through the setDatabase: method. */

[myBinder setDatabase:myDB] i

Furthermore, the DBBinder must be informed of which properties in which tables in the database it should accommodate. There are two ways to do this:

• If you can determine the list of properties that you're interested in, you should inform the DBBinder through the setProperties: method. As a convenience, the

initForDatabase:withProperties:andQualifier: method lets you initialize the DBBinder and set its DBDatabase and property list (and an optional property qualifier) in a single breath. An example of this method is given in the next section.

4-24 Chapter 4: The Database Kit

• Alternatively, you can describe the properties that you want as an expression in the database's query language, passing the expression (a string) as the argument to the evaluateString: method, as shown below:

/* Select all the properties in the "Weight" table. */

[myBinder evaluateString:"select * in Weight"];

The optional qualifier described as part of the initForDatabase:... method can be set separately, through the setQualifier: method. The qualifier, of which there can be but one at a time per DBBinder, is used to filter properties when the DBBinder is told to select data from the database. (See the "Qualification" section, below for more on the qualifier.)

Records and Containers

The pith of a DBBinder is a collection of objects that hold records from a database table.

Each object, called a record, holds one record from the database. The collection of a DBBinder's record-holding objects is stored in a container object. Record and container objects, however, aren't built into the DBBinder class-you have to specify what sorts of objects you want to assume these two roles.

Specifying a container is easy, you invoke the setContainer: method, passing an object that conforms to the DB Containers protocol. That object will be used by the DBBinder to store record objects when the DBBinder fetches from the database. Barring any specialized requirements, a DBBinder is well served using a List object as its container (DBBinder defines a List category that allows a List to pose as a DB Containers-conforming object).

You can also use a DBBinder without setting its container. For a container-less DBBinder, fetching data is done one record at a time and can only step forward through the database.

Setting a record object takes a bit more thought. There are two general approaches: You can specify an object yourself that will be copied for each record, or you can let the DBBinder create and assemble a class dynamically, instances of which it will then create to store records.

The first approach centers around the setRecordPrototype: method. To this method you pass an object that will be copied as records are fetched from the table, one copy per record.

But you're not done yet. To actually get a record's property values into a copy of the prototype record object, you must create an association between each property and one of the record object's instance variables, or between a property and a pair of methods, one to set and the other to retrieve the property's value. These associations are created through the associateRecordlvar:withProperty: and associateRecordSelectors: :withProperty:

methods. You can mix and match associations within a record object such that some properties are associated with instance variables and others are associated with method pairs, but a single property can only be associated with one variable or one pair of methods.

For example, let's say you want to access a table that contains information about convicted felons. Furthermore, you're only interested in a felon's name and the length of his or her sentence. To accommodate the records in the table you create a class called FelonRecord, for which the interface file might look like this:

@interface FelonRecord : Object

char *name;

float sentence;

@end

Having connected to the database and the table (as described in the DBDatabase class and DB Entities protocol descriptions), you would create a DBBinder object, set the record prototype, and associate the appropriate properties with the designated instance variables:

DBDatabase myDB;

myDB = [DBDatabase findDatabaseNamed:"Crime Data" connect:YES];

felonTable = [myDB entityNamed:"Convicts"];

nameProp

=

[felonTable propertyNamed:"Name"];

sentenceProp

=

[felonTable propertyNamed:"Sentence Length"];

[propList addObject:nameProp];

[propList addObject:sentenceProp];

/* Initialize the binder. */

aBinder = [[DBBinder alloc] initForDatabase:myDB withProperties:propList andQualifier:nil] ;

/* Set the container, record prototype, and associations. */

[aBinder setContainer: [[List alloc] init]];

[aBinder setRecordPrototype: [[FelonRecord alloc] init];

[aBinder associateRecordIvar:"name" withProperty:nameProp];

[aBinder associateRecordIvar:"sentence" withProperty:sentenceProp];

The DBBinder is now ready to fetch records from the table (as described in the following section).

4-26 Chapter 4: The Database Kit

The other approach to creating a record object prototype requires less work and is more adaptable, but it's also less controllable. It centers around the method

createRecordPrototype. When a DBBinder receives a createRecordPrototype message, it creates and assembles, while you wait, a class (by default, a subclass of Object) that will be used to create record objects. This new class defines a set of instance variables that match, in number, name, and type, the properties that the DBBinder knows about (as set through the methods described in the previous section, and possibly modified by

addProperty: and removePropertyAt:). When

a

record is fetched, an instance of the class is created and its instance variables are bound to the record's properties. Fetching (through the fetch method) automatically invokes createRecordPrototype, thus you needn't invoke it yourself.

You can prepare the dynamic record class through two DBBinder class methods:

• setDynamicRecordClassName: takes a string argument that's used to name the class that DBBinder will create; by default, DB Binder gives the class an arbitrary, but unique, name. The argument that you pass must itself be a unique class name-it mustn't name an existing class.

• setDynamicRecordSuperclassName: also takes a string argument that names a class, but for this method the named class must exist. It's used as the superclass for the class that DBBinder will create (which, as mentioned above, is Object by default). This is of particular use if you've created a class whose set of instance variables are known to match, to some extent, the properties in the table that you're binding to. If the set isn't complete, the subclass (the class that DBBinder will create) will be given a sufficient number of additional instance variables.

Warning: Since these are class methods, invoking either of them will affect all subsequent invocations of createRecordPrototype for all DBBinder instances. Classes that were previously created are unaffected.

Of the two approaches, the setRecordPrototype: method takes priority. Reinforcing this, you shouldn't send createRecordPrototype to a DBBinder that has previously received a setRecordPrototype: message.

Using a DBBinder

The point of all this, of course, is to gain access to the data in the actual database.

Having set up your DBBinder, you can command it to retrieve data through the select, selectWithoutFetching, and fetch methods (select performs a select and a fetch;

selectWithoutFetchingjust selects). The insert, update, and delete methods write data back to the database. In addition, the evaluateString: method can be used to command the adaptor associated with the DBBinder's DBDatabase to evaluate the given string, and thereby produce data or modify data.

After fetching data into a DBBinder's record objects, you can point to a particular record by positioning the "cursor" in the container. This is done through the DBCursorPositioning protocol methods such as setNext and setTo:. (If the DBBinder doesn't have a container, then only the setNext method can be used; in this case, setNext causes a fetch to be performed.) Having positioned the cursor, you can retrieve a DBValue object from the pointed-to record for a particular property through the valueForProperty: method. You can then examine and modify the DBValue; any changes you make will be imprinted on the record in the DBBinder and will be written back to the database when the DBBinder receives an update message.

The DBBinder class also provides an asynchronous fetch mechanism, provoked by the fetchlnThread method. When the DBBinder receives a fetchlnThread message, it creates a separate thread in which the fetch is performed. (Note that asynchronous fetching requires containers.) To check on the progress of a threaded fetch, use the method checkThreadedFetchCompletion: .

Qualification

You can give a DBBinder a DB Qualifier object through the setQualifier: or

initForDatabase:withProperties:andQualifier: method. The DB Qualifier is applied to data that's obtained through DBBinder's fetch and select methods; note, however, that it isn't used by evaluateString:.

Instance Variables

4-28 Chapter 4: The Database Kit

The DBDatabase object with which this DBBinder is associated.

A template for the DBBinder's record objects.

The repository for record objects.

The receiver of notification messages.

Im Dokument Oriented Software (Seite 27-36)