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

DBDatabase



Inherits From: Object
Declared In: dbkit/DBDatabase.h



Class Description

The DBDatabase class provides a means for reading a database model and for communicating with the adaptor that the model is built upon.  For each model that you use in your application, you need a separate DBDatabase object.

You rarely create a DBDatabase object directly in your application.  Instead, you ask the DBDatabase class to find, and return to you, the object that corresponds to a particular model file.  You do this by passing the name of the model as the first argument to the findDatabaseNamed:connect: class method.  DBDatabase objects that are retrieved through this method are global to your application:  All invocations of the method with the same model name argument will return the same DBDatabase object.

Having found the DBDatabase object that you want, you use it to retrieve the entity objects that are stored in the model, through the getEntities: and entityNamed: methods.  These entity objects, and the property objects that are gotten from them, are used to configure instances of (typically) DBRecordList, which are used to store data that's retrieved (or "fetched") from the server.

However, before data can be fetched, your DBDatabase object must be connected to the server.  There are three methods that form this connection:

findDatabaseNamed:connect:.  You can connect the object when you find it by passing YES as the second argument to findDatabaseNamed:connect:.
connect.  If you want to defer the connection--to just before the first data fetch, for example--you can pass NO to the findDatabaseNamed:connect: method and then connect later by sending a connect message to your DBDatabase object.
connectUsingAdaptor:andString:.  In forming a connection to the server, the findDatabaseNamed:connect: and connect methods use the adaptor name and login string information that's found in the DBDatabase's model.  The connectUsingAdaptor:andString: method lets you override these default settings while attempting a connection.

The three tasks of (1) finding a model, (2) getting its entities, and (3) connecting to the server are, typically, the extent of a DBDatabase object's employment in an application.  (Furthermore, if you use the Database Kit Palette to configure your application's user interface, these three tasks are taken care of for you.)  All the other methods defined by DBDatabase either support these three operations or are designed to be used only if you need to initiate and control data transactions directly.

There is, however, one more thing that the DBDatabase object does, albeit indirectly:  It allows a delegate object that receives a series of messages that log watershed moments and allow some mediation if a transaction is confounded.  See the delegate method descriptions at the end of this class description for more on information.



Instance Variables

id delegate;


delegate The object that receives notification messages



Method Types

Reporting what's available + adaptorNames
+ databaseNamesForAdaptor:
Initializing an instance initFromFile:
Describing the model source directory
name
currentAdaptorName
defaultAdaptorName
defaultLoginString
currentLoginString
loginStringForUser:
Describing the database model entityNamed:
getEntities:
Revising the data dictionary emptyDataDictionary
loadDefaultDataDictionary
Connecting to the database + findDatabaseNamed:connect:
connect
connectUsingAdaptor:andString:
disconnect
disconnectUsingString:
isConnected
connectionName
Managing transactions beginTransaction
rollbackTransaction
commitTransaction
isTransactionInProgress
areTransactionsEnabled
enableTransactions:
Using a delegate delegate
setDelegate:
Evaluating an arbitrary string evaluateString:
Controlling the user interface arePanelsEnabled
setPanelsEnabled:



Class Methods

adaptorNames
+ (const char **)adaptorNames

Returns a NULL-terminated array of strings that name the adaptors that are available to the DBDatabase class.  The array is compiled by searching the application's main bundle and then the directories ~/Library/Adaptors, /LocalLibrary/Adaptors, and finally /NextLibrary/Adaptors.   The names in the array are given without pathnames and without the ".adaptor" file extensions.

See also:  + databaseNamesForAdaptor:



databaseNamesForAdaptor:
+ (const char **)databaseNamesForAdaptor:(const char *)anAdaptorName

Returns a NULL-terminated array of strings that name the models that the named adaptor serves.  The class constructs the list by searching the application's bundle and then the directories ~/Library/Databases, /LocalLibrary/Databases, and finally /NextLibrary/Databases.   The names in the array are given without pathnames and without the ".dbmodel" or ".dbmodela" file extentions.

If the argument is NULL, the method returns the names of all the models it can find, regardless of the adaptors upon which they're built.

See also:  + adaptorNames



findDatabaseNamed:connect:
+ findDatabaseNamed:(const char *)modelName
connect:(BOOL)flag

Returns a DBDatabase object for the given model name.  The model is searched for in the locations described in the databaseNamesForAdaptor: class method.  Repeated invocations of this method with the same modelName argument will return the same DBDatabase object.

If flag is YES, the object attempts to connect to the server that lies beneath the adaptor upon which the model is built.

This method returns nil if the model wasn't found, or if a connection was attempted but failed.

See also:  + databaseNamesForAdaptor:, connect, connectUsingAdaptor:andString:



Instance Methods

arePanelsEnabled
(BOOL)arePanelsEnabled

Returns YES if the adaptor upon which the DBDatabase object is built is allowed to display panels in the user interface.  By default, panels are enabled; you can disallow by passing NO to the setPanelsEnabled: method.

See also:  setPanelsEnabled:



areTransactionsEnabled
(BOOL)areTransactionsEnabled

Returns YES if the DBDatabase's adaptor allows transaction contexts to be established.  The method returns NO if transactions aren't allowed or if the DBDatabase isn't currently connected to the server.

See also:  enableTransactions:



beginTransaction
(BOOL)beginTransaction

Tells the adaptor to set up a transaction context.  Exactly how the transaction is implemented depends on the server; typically, a virtual copy of subsequently fetched data is created (by the server), thus "stabilizing" the data while the transaction is in progress.  When you've finished reading and modifying the data, you send commitTransaction to the DBDatabase, which attempts to write the data back to the server, or rollbackTransaction, which simply throws the copy away.  You're allowed to set up only one transaction context at a time.

Returns YES if the transaction context is successfully initiated; the method will fail, and return NO, if the adaptor doesn't allow transactions, if the DBDatabase isn't connected to the server, or if a transaction context has already been initiated.

See also:  commitTransaction, rollbackTransaction



commitTransaction
(BOOL)commitTransaction

Causes a transaction started with beginTransaction to be committed.  Any changes to the data that have been queued up since the previous beginTransaction will be irreversibly made in the database.  Returns YES if the transaction was committed.  If the server rejects the data,  this method returns NO.

Important:  A return of NO does not mean that the transaction has been closed.  It remains open. That way, the application retains the option to take remedial action before trying again to commit.  The transaction will remain open until rollbackTransaction is called.

See also:  beginTransaction, rollbackTransaction



connect
(BOOL)connect

Opens a connection to the server, using the default adaptor name and login string.    Returns YES if the connection was successfully established by this method.  Note well that this method returns NO if the DBDatabase is already connected.

See also:  defaultAdaptorName, defaultLoginString, disconnect



connectionName
(const unsigned char *)connectionName

Returns the name of the adaptor's current connection to the server (as defined by the adaptor itself).  If the DBDatabase isn't connected, this returns an empty string.



connectUsingAdaptor:andString:
(BOOL)connectUsingAdaptor:(const char *)adaptorName
andString:(const unsigned char *)aString

Opens a connection to the server using the adaptor identified by adaptorName, and the login string aString.  You must supply the adaptor name; if the login string aString is NULL, the method uses the default login string.  You should only invoke this method if you want to connect to an adaptor other than the one named in the model through which the DBDatabase was created.  For a "normal" connection, use the findDatabaseNamed:connect: class method, or the connect instance method.

Returns YES if the connection is made.  Note well that this method returns NO if the DBDatabase is already connected.

See also:  connect, disconnect, disconnectUsingString:



currentAdaptorName
(const char *)currentAdaptorName

Returns the name of the adaptor through which the DBDatabase is connected to the server.  This method returns NULL if the DBDatabase isn't currently connected.

Typically, the current adaptor is the same as the default adaptor--in other words, it's the adaptor that's named in the DBDatabase's model.  The one case in which the current and default adaptors may differ is if the DBDatabase was connected through the connectUsingAdaptor:andString: method.

See also:  defaultAdaptorName, defaultLoginString, currentLoginString



currentLoginString
(const unsigned char *)currentLoginString

Returns the login string that was used to form the connection to the server.  If the DBDatabase isn't currently connected, this method returns NULL.

Typically, the current login string is the same as the default login string--in other words, it's the login string that's named in the DBDatabase's model.  The one case in which the current and default login strings may differ is if the DBDatabase was connected through the connectUsingAdaptor:andString: method.

See also:  defaultLoginString, defaultAdaptorName, currentAdaptorName



defaultAdaptorName
(const char *)defaultAdaptorName

Returns the name of the adaptor that's named in the DBDatabase's model.  This is the adaptor that, by default, is used to form a connection to the server.  To use some other adaptor, you must name it in an invocation of the connectUsingAdaptor:andString: method.

See also:  currentAdaptorName, defaultLoginString, currentLoginString



defaultLoginString
(const unsigned char *)defaultLoginString

Returns the login string that's given in the DBDatabase's model.  This is the login string that, by default, is used to form a connection to the server.  To use some other string, you must pass it in an invocation of the connectUsingAdaptor:andString: method.

See also:  currentLoginString, defaultAdaptorName, currentAdaptorName



delegate
delegate

Returns the DBDatabase's delegate.

See also:  setDelegate:



directory
(const char *)directory

Returns the full pathname of the model file that the DBDatabase represents.

See also:  name



disconnect
(BOOL)disconnect

Closes the connection to the database.  Returns YES if the connection was successfully closed.

See also:  disconnectUsingString: connect, + findDatabaseNamed:connect:



disconnectUsingString:
(BOOL)disconnectUsingString:(const unsigned char *)aString

Closes the connection to the database by sending it the command aString.  Returns YES if the connection was successfully closed.

See also:  disconnect, connect, + findDatabaseNamed:connect:



emptyDataDictionary
emptyDataDictionary

Frees the information that the DBDatabase found in its model.  Specifically, the entity names (and property names), adaptor name, and login string are all erased.  You should only need to invoke this method if you want to load the server's default data dictionary (and that should be rare).  Returns self.

See also:  loadDefaultDataDictionary



enableTransactions:
(BOOL)enableTransactions:(BOOL)flag

Controls the right to use transactions--that is, permits use of the methods beginTransaction, commitTransaction, and rollbackTransaction--according to the value of flag.  Returns YES if the adaptor is able to comply, NO otherwise.

See also:  areTransactionsEnabled



entityNamed:
(id <DBEntities>)entityNamed:(const char *)aName

Returns the entity named aName from the DBDatabase object's list of entities, or nil if it isn't found.  The list of entities is gotten from the DBDatabase's model.

See also:  getEntities:



evaluateString:
(BOOL)evaluateString:(const unsigned char *)aString

Asks the server to evaluate the string aString, which must be a valid statement in the server's query language.

Warning: You can't use this method to fetch data into a DBRecordList; to retrieve fetched data through this method, you must capture it in a DBBinder object.
Returns YES if the string is successfully evaluated.  If the delegate implements the method db:willEvaluateString:usingBinder:, the evaluation is permitted only if the delegate returns YES to that notification.
See also:  db:willEvaluateString:usingBinder: (delegate method)
getEntities:
(List *)getEntities:(List *)aList

Fills aList with the DBEntities objects that represent the model's entities.  The method also returns the List.

See also:  entityNamed:



initFromFile:
initFromFile:(const char *)aPath

Initializes and returns the DBDatabase object from the database model information in the bundle identified by the path aPath. Model information (database name, login string, adaptor name, and entities) are read from the file.  You rarely should need to invoke this method.  In general, you should use the class method findDatabaseNamed:connect: to get a DBDatabase object.

See also:  + findDatabaseNamed:connect:



isConnected
(BOOL)isConnected

Returns YES if the DBDatabase is connected to the server.

See also:  + findDatabaseNamed:connect:, connect



isTransactionInProgress
(BOOL)isTransactionInProgress

Returns YES if a transaction has been started (by beginTransaction) and has not yet been committed or rolled back.

See also:  beginTransaction, commitTransaction, rollbackTransaction



loadDefaultDataDictionary
loadDefaultDataDictionary

Reads the server's data dictionary (its list of entities and properties) and fills the DBDatabase with this information.  You should always precede the method with an invocation of emptyDataDictionary (the DBDatabase's current dictionary must be empty for this method to succeed).  This method has no effect if the DBDatabase object isn't connected to the server.  You should rarely need to invoke this method.  Returns self.

See also:  emptyDataDictionary



loginStringForUser:
(const unsigned char *)loginStringForUser:(const char *)aUser

Returns the login string for the database server user identified by aUser.



name
(const char *)name

Returns the name of the model that the DBDatabase object represents.

See also:   + findDatabaseNamed:connect:, directory



rollbackTransaction
(BOOL)rollbackTransaction

Causes the server to roll back all changes since a preceding beginTransaction.  Returns YES if the rollback was successful. Returns NO if the server couldn't roll back the transaction, or if there wasn't a transaction in progress.

See also:  beginTransaction, commitTransaction, dbWillRollbackTransaction: (delegate method)



setDelegate:
setDelegate:anObject

Makes anObject the DBDatabase's delegate.  Returns self.

See also:  delegate



setPanelsEnabled:
setPanelsEnabled:(BOOL)flag

Tells the DBDatabase to suppress (or not) the attention panels that it displays (in response to server errors, for example).  By default, panels are enabled.  You should disable a DBDatabase's panels if you're creating an application that must run on its own, or that doesn't have a graphic interface.  Returns self.

See also:  arePanelsEnabled, db:notificationFrom:message:code: (delegate method)



Methods Implemented by the Delegate

db:log:
db:aDatabase log:(const char *)fmt, ...

Invoked when the DBDatabase experiences a particularly important, stressful, or otherwise notable moment.  The second argument is a log entry that can be written to a file, displayed in the user interface, spat to standard out, or placed on a shelf along with the object's other trophies and mementoes.  The format of the log entry argument is in the varargs style; the example implementation shown below demonstrates how to turn the argument into text (which, here, is displayed in the user interface):

@implementation Control (DatabaseDelegate)
- db:aDatabase log:(const char*)format, ...
{
va_list args;
static char buf[1024];
va_start(args, format);
vsprintf(buf, format, args);
if ([self respondsTo:@selector(setStringValue:)])
[self setStringValue:buf];
else
syslog(LOG_NOTICE, buf);
return self;
}
@end

The operations that cause this method to be invoked are

Connecting to and disconnecting from the server
Enabling transactions
Initiating, committing, and rolling back a transaction
Receiving a notification message (see the db:notificationFrom:... method)
Fetching and saving modified data (through a DBRecordList, for example)
Evaluating a string

The return value is ignored.



db:notificationFrom:message:code:
(BOOL)db:aDatabase
notificationFrom:anAdaptor
message:(const unsigned char *)msg
code:(int)errorCode

Invoked (by the adaptor) when the server encounters an exceptional situation.  The arguments are:

aDatabase is the DBDatabase object.
anAdaptor is the object that represents the adaptor.
msg is a string that describes the error.
errorCode is an integer constant, defined by the server, that represents the error.

The return value is ignored.

If the delegate doesn't implement this method, and if panels are enabled, an attention panel that displays the msg and errorCode values is presented to the user.

See also:  setPanelsEnabled:



db:willEvaluateString:usingBinder:
(BOOL)db:aDb
willEvaluateString:(const unsigned char *)aString
usingBinder:aBinder

Invoked before aString, which must be expressed in the server's query language, is sent to the server for evaluation.  Whether the string is actually sent depends on the value that's returned by this method:  If this method returns YES (or if it isn't implemented), the string is sent; a return of NO prevents the evaluation.

This method is invoked when the DBDatabase receives an evaluateString: message, and when the DBDatabase's adaptor is about to perform a data operation, such as selecting or updating.

See also:  evaluateString:



dbDidCommitTransaction:
dbDidCommitTransaction:aDatabase

Invoked just after a transaction is committed.   The return value is ignored.

See also:  dbWillCommitTransaction: (delegate method)



dbDidRollbackTransaction:
dbDidRollbackTransaction:aDatabase

Invoked just after a transaction is rolled back.  The return value is ignored.

See also:  dbWillRollbackTransaction: (delegate method)



dbWillCommitTransaction:
dbWillCommitTransaction:aDatabase

Invoked just before a transaction is committed.   The return value is ignored.

See also:  dbDidCommitTransaction: (delegate method)



dbWillRollbackTransaction:
dbWillRollbackTransaction:aDatabase

Invoked just before a transaction is rolled back.  The return value is ignored.

See also:  dbDidRollbackTransaction: (delegate method)