t e m p o r a l 
 d o o r w a y 

Overriding The OpenCursor() Method

 

Introduction

There are some special dataset application where you might need to know when a dataset is made active or inactive through a change to the Active property.

My project required a dataset which created a physical table when the component was instantiated, said table to be destroyed when the component was destroyed.

Under normal circumstances, one looks for a method whose name is Set<propertyname> to override for the purpose of trapping changes to the property. However, the TDataSet class is non-orthogonal in that a table can be opened both by setting the Active property or calling the Open method. For this reason, a method called InternalOpen is shared by both SetActive() and Open().

A chapter in the "Delphi Developer's Handbook" discusses establishing new classes derived from TCustomDataSet, and it recommends overriding the InternalOpen method. However, my table class is derived from a third party descendant of TTable and, for whatever reason, it seems to override the OpenCursor method rather than InternalOpen. I therefore chose to follow their lead.

The Implementation

The implementation overrides the void __fastcall OpenCursor(bool theInfoQuery) and void __fastcall CloseCursor(void) methods.

Because this component creates a table when it is instantiated and made active, I do not allow it to be made active at design time. This is done by...

 if (ComponentState.Contains(csDesigning)) // Can't open at design time, which would create a table
 {
  SetState(dsInactive);
  return;
 };

One must be careful because there are certain operations which provoke a call to OpenCursor, and if you perform them, you will end up with an endless recursive loop (BatchMove is one of these methods). If you must call one of these methods, bracket the call with a guard variable to prevent recalling that method until the operation is complete, for instance:

   if (!myCopyInProgress)
   {
      myCopyInProgress = true;
      BatchMove(OtherTable,batCopy);
      myCopyInProgress = false;
   };

   Inherited::OpenCursor(theInfoQuery);

which basically passes the batch move OpenCursor() to the inherited method. The "myCopyInProgress" variable should be initialized in the constructor to false, so that the first call (and subsequent calls) to OpenCursor() will perform the needed operations.

Closing the cursor in my project required me to delete the created physical table, so I needed to override CloseCursor and to check to make sure the table was being closed because the component was being destroyed (ComponentState.Contains(csDestroying)) before deleting the table. You may or may not have a need to override that method. Once again, remember to call the inherited method from your method.

Conclusion

You may never need to create a class such as this, but if you do, you will not find it so difficult if you follow the steps shown above.

Copyright © 2004 by Mark Cashman (unless otherwise indicated), All Rights Reserved