Custom Variant Wrapper for TDataset - Part 4

In Part 3 we discussed clearing and copying our custom variant.  Next I am going to show you how to implement dynamic properties for our TDataset wrapper.  If you remember from the introduction to this series of articles, I wanted to be able to get the value of a dataset’s fields’ values using the name of the field as the property name.  Like this: variant.field_name.

To implement dynamic properties for a variant you need to derive the custom variant class, in this case TDatasetVariant from TInvokeableVariantType or TPublishableVariantType rather than TCustomVariantType.  So we need to change our class declaration to this:


TDatasetVariant = class(TPublishableVariantType)
end;

I chose TPublishableVariantType because it allows us to expose published properties of the TDataset as well as our custom, dynamic properties with very little extra work.  More about that in a bit.

There are two methods that we need to override to implement our dynamic properties; GetProperty and SetProperty.  These methods return the value of the property as a variant and set the value of the property from a variant respectively.

GetProperty takes three arguments; Dest which is the variant that will receive the properties value, V which is an instance of our custom variant and Name which is the name of the dynamic property.  Since Delphi is case insensitive Name is forced to all upper case characters before GetPropety is called.  The implementation of this method can be as simple or as complicated as need be.  For the purposes of our TDataset wrapper we need only use Name to find the TField with the matching field name and return its value.  If we fail to find a field with the given name we will return the value of the published TDataset property corresponding to Name.  The implementation of GetProperty looks like this:


function TDatasetVariant.GetProperty(var Dest: TVarData; const V: TVarData;
const Name: String): Boolean;
var
ds: TDataset;
fld: TField;
begin
ds := TDatasetData(V).VDataset;
fld := ds.FindField(Name);
if (Assigned(fld)) then
begin
// If the property name is a field name from the dataset, return a
// reference to the field.
Result := True;
Variant(Dest) := fld.Value;
end else
// If the name of the property is not a field name, return the value
// of one of the published properties.
Result := inherited GetProperty(Dest, V, Name);
end;

You will notice that if a field with the given property name cannot be found I call the inherited GetProperty method.  This method will return the value of the published TDataset property corresponding to Name.

SetProperty also takes three arguments; V which is an instance of our custom variant, Name which is the name of the dynamic property and Value which is a variant containing the new value.  The implementation of SetProperty looks like this:


function TDatasetVariant.SetProperty(const V: TVarData; const Name: string;
const Value: TVarData): Boolean;
var
ds: TDataset;
fld: TField;
begin
ds := TDatasetData(V).VDataset;
fld := ds.FindField(Name);
if (Assigned(fld)) then
begin
fld.Value := Variant(Value);
Result := True;
end else
// If the name of the property is not a field name, set the value
// of one of the published properties.
Result := inherited SetProperty(V, Name, Value);
end;

In order for the inherited GetProperty and SetProperty methods to work they need to know which object to get the published properties from.  In order to provide that information we need to implement the GetInstance method.  This method simply returns a reference to the object to be used by GetProperty and SetProperty.  Our implementation of GetInstance looks like this:


function TDatasetVariant.GetInstance(const V: TVarData): TObject;
begin
Result := TDatasetData(V).VDataset;
end;

Now the inherited GetProperty and SetProperty methods will use the reference to our wrapped TDataset to find any published properties.

Leave a Reply