TPhKeyPtrs, TPhDbKeys, the Key manager:

How to use the Database without making any database calls

TPhDbKeys, TPhKeyPtrs, and Reading

TPhDbKey is an abstract base class which represents a one-to-one correspondence with the concept of a primary key in an SQL database, such as that of the Phobos database. For any TPhDbKey object, there should be one and only one object that we can extract from the database; and this object must be the same whenever we ask for it, even if more objects have been added to the database in the meantime.

A TPhDbKey (or more accurately one of its derived classes, since TPhDbKey is an abstract class) can be passed around, saved, whatever, like any ordinary TObject, without accessing the database.

A TPhKeyPtr takes a TPhDbKey, uses it to get or create its C++ object, and then acts as a pointer to that object. C++ operators have been overridden, so that you can use the dereference(*) and pointing (->) operators on this class. TPhKeyPtr is a template class, with its template parameter indicating what it points to; eg the type TPhKeyPtr<TPhFECDetector> is a key pointer to an FECDetector. If key is a TPhDbKey, then the C++ statement:
TPhKeyPtr<TPhFECDetector> mypointer(key);
creates a new key pointer, mypointer, which points to the object referenced by key; if the object had not previously been accessed, this statement will implicitly go to the database, and read it from there. After this is done, one could use:
mypointer->GetFEC(3);   // Returns a pointer to FEC 3
to access the object pointed to.

Writing to Database

Often people will want to write to the database. This requires some care, since usually a key can only point to specific kinds of objects, and the writers of the keys and objects must take care to do that correctly (or else the program will probably crash, or if its nice give some error message). That said, writing to database is a matter of creating a correspondence between an object and a key. If key is a TPhDbKey object and runptr is a pointer to the object (here of type TPhRun) we wish to make key the key of, then:
TPhKeyPtr<TPhRun> newpointer(key,runptr);
will create the correspondence and in the process write the object to the database.

Key Selectors

Often we do not know a priori which key corresponds directly to the object we want. We want the 'best' object given certain information; for example, we might want the best set of pedestals that we have for a given run number. This is where the TPhDbKeySelector class comes in. A KeySelector knows how to get the best key based on some information; again it is an abstract base class. Note some crucial differences from a TPhDbKey: for a given selector, the best object could change, if a new, better choice gets added to the database; and more than one selector can correspond to the same object.

Usually a key selector is returned from a specific TPhDbKey's Select method and doesn't exist very long, but in principle it could be passed around, read and written, etc., like any other TObject. An example of a common use of a selector:
TPhKeyPtr<TPhPedestalSet> peds(TPhCalKey::Select("SIPED",2332));
will return a KeyPtr to the 'best' pedestal calibration set it can find for run 2332. Here, the TPhDbKeySelector does not appear directly, but is returned from TPhCalKey::Select and passed to the constructor of the KeyPtr.

Under the hood, this call will result in at least one and possibly two calls to the database: first the KeySelector class will get called to query the database to find the best key, which it will pass back internally; that key will then get used as above to get the object, which might be cached.

This page maintained by George Heintzelman.