How to : Implementing foxpro's scatter and gather memvar in delphi

Опубликовано: 05 Октябрь 2024
на канале: How to : Tips and Trick
122
1

Implementing foxpro's scatter and gather memvar in delphi

Implementing FoxPro's Scatter and Gather Memvar in Delphi.

Delphi Developer February 2001

Copyright Pinnacle Publishing, Inc. All rights reserved.



Implementing FoxPro's Scatter and Gather Memvar in Delphi

Steve Zimmelman



Technology is always moving forward, usually leading to more productive development. However, there are times when reaching into the past can be helpful, too. Replicating or comparing table data in FoxPro was a fairly simple task. Steve Zimmelman argues that perhaps this technology is worth reaching back.



FoxPro's Scatter and Gather commands were always useful for copying records from one table to another, comparing data, or record replication among multiple tables. For those of you who haven't had the pleasure of working with FoxPro, the Scatter and Gather commands work like this.

Suppose you need to copy a record from one table to another. You'd do something like:

Select Table1

Scatter Memvar

Select Table2

Gather Memvar

The Scatter command reads all of the fields for the current

record and places them into memory variables. Each variable that's

created with Scatter has the same name as the field from which it

originated. The Gather command updates the current record with memory variables that have names that correspond to the fields. So if Table1 has the fields Name, Address, and Phone, and the variables Name, Address, and Phone exist, then when the Gather command is executed it updates the record with the value stored in those variables.

There are many ways to accomplish this with Delphi, but there's nothing natively supplied in the VCL that works at the TDataSet level. In my latest application endeavor, I had a need for the old Scatter and Gather functionality. So, I ended up writing my own ScatterMemvar and GatherMemvar methods.



Creating the Scatter and Gather functions

Both of these methods are wrappers for an object called TMemvar. TMemvar maintains a dynamic array of a record called TMemVarFields. Each element of the MemVarFields array contains the FieldName, DataType, and Value of a corresponding field in a DataSet. So each instance of TMemvar contains the data from a single table record.



Type

MemVarField = Packed Record

FieldName : String;

Value : Variant ;

DataType : TFieldType;

End;

TMemVarFields = Array Of TMemVarField ;

When the ScatterMemvar function is invoked, it creates an instance of TMemvar and returns a pointer to that instance. When TMemvar is created, it loads the fields from the designated DataSet into the array. To avoid DataSet duplication, each instance of TMemvar is identified by its DataSet property. Before a new instance of TMemvar is created, a search is performed for a matching DataSet in all existing instances of TMemvar. If one is found, the matching instance is reused. If not, a new instance is created.

Function ScatterMemvar(DataSet:TDataSet) : TMemVar ;

Begin

If (DataSet = Nil) Then

Raise Exception.Create('DataSet Cannot Be NIL');

// Reuse the object if it already exists.

Result := FindMemvarObject(DataSet);

If (Result = Nil) Then Begin

Result := TMemvar.Create(DataSet) ;

End Else Begin

Result.LoadFieldData ;

End;

End;

Constructor TMemVar.Create(DataSet:TDataSet) ;

Begin

FFlds := Nil ;

FDataSet := DataSet ;

If (FDataSet = Nil) Then Begin

Raise Exception.Create('DataSet Cannot Be NIL');

End;

If (FScatterList = Nil) Then

FScatterList := TList.Create ;

FScatterList.Add(Self);

LoadFieldData ;

End;

Procedure TMemVar.LoadFieldData ;

Var

i : Integer ;

Begin

If Not DataSet.Active Then DataSet.Open ;

FFlds := Nil ;

// set the length for the record array.

SetLength(FFlds,FieldCount);

For i := 0 To (DataSet.FieldCount-1) Do Begin

With DataSet.Fields[I] Do Begin

FFlds[i].FieldName := FieldName ;

FFlds[i].Value := Value;

FFlds[i].DataType := DataType ;

End;

End;

End;

Normally when you create an object, it's necessary to free the object when it's no longer needed. But the unit that contains the code for this object maintains its own internal list of TMemvar instances and destroys them automatically when the application closes. So you can free the objects when they aren't needed, or ignore them and let the unit take care of itself.

To manage the TMemvar objects that are created for each ScatterMemvar usage, I add each new instance of TMemvar to FScatterList, a type of TList. The unit that handles all of this code contains Initialization and Finalization sections. The Initialization makes sure FScatterList is set to Nil. This is done so that the Create method of TMemvar can interrogate the value of FScatterList and create an instance of it only when necessary. This keeps the resources that the unit requires down to a..