Sie sind auf Seite 1von 2

How to: Clone TField and TDataset fields structure

This is just a quick tip on how to copy field structure between TDatasets. The interesting part is the "CloneField"
function that duplicates the exact class of a TField from one dataset to another.

First the loop that iterates through a source dataset fields collection and clones each item (TField) to  another
dataset, the destination. It takes as parameters a source TDataset from where fields structure will be read, a
destination TDataset where fields will be created and a boolean that instructs the procedure to add the fields to the
existing structure or exactly clone the source structure.

procedure CopyFields(SourceDataset, DestDataset: TDataset; doAdd: Boolean);


var i,p: integer;
    Fld: TField;
    dFld: string;
begin
  if not doAdd then DestDataset.Fields.Clear;
  for i:=0 to SourceDataset.Fields.Count-1 do
    begin
    if Assigned(DestDataset.Fields.FindField(SourceDataset.Fields[i].FieldName)) then
       Continue;
    Fld := CloneField(SourceDataset.Fields[i], DestDataset.Fields.Dataset);
    Fld.DataSet := DestDataset.Fields.Dataset;
    end;
end;

Notice the lines:

?
1Fld := CloneField(SourceDataset.Fields[i], DestDataset.Fields.Dataset);
2Fld.DataSet := DestDataset.Fields.Dataset;
The first is the call to "CloneFields" function that creates and returns a new TField object and the second that
actually binds the field to the destination dataset. This is required in order to have a functional field in the dataset.
Do not rely to the owner of the field that could be any TComponent, ie the form, which is the owner of persistent
fields we create with the Delphi form designer.

Now, the function that creates an exact TField descendant class based on another one:

?
function CloneField(Source: TField; AOwner: TComponent): TField;
 
  procedure SetProp(Name: string);
  var V: variant;
      PropInfo: PPropInfo;
  begin
   PropInfo := TypInfo.GetPropInfo(Source, Name);
   if PropInfo <> nil then
     try V := TypInfo.GetPropValue(Source,Name);
      if not VarIsNull(V) then
         TypInfo.SetPropValue(Result,Name,V);
     except
      ; //just kill exception
     end;
  end;
 
begin
  Result := TFieldClass(Source.ClassType).Create(AOwner);
 
  Result.Alignment              := Source.Alignment;
  Result.AutoGenerateValue      := Source.AutoGenerateValue;
  Result.CustomConstraint       := Source.CustomConstraint;
  Result.ConstraintErrorMessage := Source.ConstraintErrorMessage;
  Result.DefaultExpression      := Source.DefaultExpression;
  Result.DisplayLabel           := Source.DisplayLabel;
  Result.DisplayWidth           := Source.DisplayWidth;
  Result.FieldKind              := Source.FieldKind;
  Result.FieldName              := Source.FieldName;
  Result.ImportedConstraint     := Source.ImportedConstraint;
  Result.LookupDataSet          := Source.LookupDataSet;
  Result.LookupKeyFields        := Source.LookupKeyFields;
  Result.LookupResultField      := Source.LookupResultField;
  Result.KeyFields              := Source.KeyFields;
  Result.LookupCache            := Source.LookupCache;
  Result.ProviderFlags          := Source.ProviderFlags;
  Result.ReadOnly               := Source.ReadOnly;
  Result.Required               := Source.Required;
  Result.Visible                := Source.Visible;
 
  SetProp('EditMask');
  SetProp('FixedChar');
  SetProp('Size');
  SetProp('Transliterate');
  SetProp('DisplayFormat');
  SetProp('EditFormat');
  SetProp('Currency');
  SetProp('MaxValue');
  SetProp('MinValue');
  SetProp('Precision');
  SetProp('DisplayValues');
  SetProp('BlobType');
  SetProp('ObjectType');
  SetProp('IncludeObjectField');
  SetProp('ReferenceTableName');
  SetProp('Active');
  SetProp('Expression');
  SetProp('GroupingLevel');
  SetProp('IndexName');
end;

The first line of code is the one that creates a new TField descendant from the actual source field class.
Then is the block of base TField common properties assignement, followed by a block of property assignements
using runtime  library information (TypInfo) for properties that MAY exist in the actual class. If some of the
properties do not exist in the actual class, then they are simply ignored.

Some things to remember:


1.The "doAdd" parameter in "CopyFields" when True results to fields added to the destination fields structure,
whilst False forces first to clear the destination fields collection resulting to an exactly same field structure to the
destination dataset as the source one.
2.DestDataset has to be inactive in order to call either of the above functions.
3.In "CloneField", if used stand-alone,  "AOwner" represents the TComponent parameter that will be responsible for
freeing the field. Usually you will pass the TDataset that the resulting field belongs to, so when the dataset closes it
will also be freed.

http://delphi-inspired.blogspot.com/2012/04/how-to-clone-tfield-and-tdataset-fields.html

Das könnte Ihnen auch gefallen