July 1998

Automating table activation

by Mark G. Wiseman

Whenever you're working with classes derived from TDataSet, such as TQuery and TTable, you often need to open and close their underlying database tables. To do so, you can use the Open and Close methods of the TDataSet class. Calling Open and Close has the same effect as setting the Active property of TDataSet to True and False, respectively. You may wonder why you'd repeatedly open and close a table. One reason is to save system resources--keep an infrequently-used table closed and open it only when you need it. Or, you may want to modify the table in some way that requires you to first close the table.

 

Manually activating a table

For an example, consider how you'd switch between a local and network database. You can easily accomplish this switch by changing the value of the DatabaseName property of a TTable component. However, if you attempt to change DatabaseName before closing the table, an exception will occur. To prevent this problem, you'll need to determine whether the table is open or closed before you close it. You must also remember to restore the previous state of the table when you're finished. The code in Listing A shows how to switch databases.

Listing A: Changing the database for a TTable

ChangeDatabase(TTable *myTable, 
	String dbName)
   {
   bool holdActive = myTable->
	Active;
   myTable->Active = false;
   myTable->DatabaseName = dbName;
   myTable->Active = holdActive;
   }

A better solution: the TDSActive Class

Setting the open or closed state of a table, then restoring the previous state is a common and error-prone activity. However, TDSActive, a very simple class shown in Listing B, makes your code easier to write. It sets and restores the table state, thereby reducing errors.

Listing B: The TDSActive class

#ifndef TDSActiveH
#define TDSActiveH

#include <db.hpp>


class TDSActive
   {
   public:
      TDSActive(TDataSet *dataset, 
	bool active = true);
      ~TDSActive();

   private:
      TDataSet *dataset;
      bool holdActive;
   };

inline TDSActive::TDSActive(TDataSet 
	*dataset, bool active) :
		 dataset(dataset)
   {
   holdActive = dataset->Active;
   dataset->Active = active;
   }

inline TDSActive::~TDSActive()
   {
   dataset->Active = holdActive;
   }

#endif

The TDSActive constructor accepts two arguments. The first, dataset, is a pointer to a TDataSet or a class derived from TDataSet. The second, active, is a bool variable that determines whether the TDataSet will be made active or inactive. The latter argument defaults to True. To open a TTable object pointed to by myTable, you'd write the code

 

TDSActive(myTable)
To close the TTable object, you'd write

TDSActive(myTable, false);
The TDSActive constructor remembers the open or closed state of the table by storing the table's Active property in the bool variable, holdActive. Finally, when the TDSActive object goes out of scope, the destructor restores the table's Active property using holdActive.

Listing C shows the code from Listing A rewritten to take advantage of TDSActive. The code no longer cares about the current state of the object pointed to by myTable. In addition, you don't need to worry about restoring that state after changing databases.

Listing C: Changing the database for a TTable using TDSActive

ChangeDatabase(TTable *myTable,
	 String dbName)
   {
   TDSActive(myTable, false);
   myTable->DatabaseName = dbName;
   }

To use TDSActive, you need to declare it in the header file, as shown in Listing B. There is no source file. TDSActive takes advantage of the C++ rules concerning the creation and destruction of objects on the stack. You benefit because it makes working with database tables a little simpler.