Creating Calculated Fields at runtime

I think I understand the problem.  It sounds like when you copy the
TDataSet you don't copy the TField objects or the events.  Those are two
separate issues.

If you did not use the Assign method of the TDataSet, then you probably
put yourself through more work than necessary and the events and fields
did not get copied.  The first suggestion I have is to use
NewDataSet.Assign(SomeDataSet) so that all properties, fields, and
events will be copied.

If for some reason you don't do this, here is how to do what you asked:

As for copying the TField objects, you must first ensure that the new
TDataSet descendant (i.e., TTable or TQuery) is closed.  Then do
something like this:

procedure MakeNewFields;
var
  MyField : TField;
  i : integer;
begin
  for i := 0 to MyDataSet.FieldCount - 1 do
  begin
    MyField := MyDataSet.Fields[i].Create(Self);
    MyField.Assign(MyDataSet.Fields[i];
    MyField.DataSet := NewDataSet;
  end;
end;

If I'm not mistaken, this should duplicate the TField objects associated
with the TDataSet.  By the way, using create this way does not replace
the original TField object; create always creates and returns a pointer
to a new instance of the given type.  The only drawback to this that the
new fields will not have names.  If you wish to access these fields, you
can only access them with NewDataSet.Fields[?] or
NewDataSet.FieldByName('FieldName').

All you need to do to make the new dataset use the old event handler is
to think of the event handlers as objects--which in fact, they are.

  NewDataSet.OnCalcFields := OldDataSet.OnCalcFields;
  NewDataSet.BeforePost := OldDataSet.BeforePost;

Again, this code is not necessary if you use TDataSet.Assign.

All of this brings up another problem.  Your OnCalcFields event handler
probably looks like this:

procedure TDataModule1.OldDataSetOnCalcFields(DataSet: TDataSet);
begin
  OldDataSetFieldName.Value := { Some calculated value }
end;

This is going to be a problem whether or not you use TDataSet.Assign as
I suggested above.  When the event handler is called for the new
dataset, it executes code which affects the old dataset.  This is easy
to get around, but it does require anyone who uses your component to
write ALL of their event handlers (not just OnCalcFields) this way:

procedure TDataModule1.OldDataSetOnCalcFields(DataSet: TDataSet);
begin
  DataSet.FieldByName('FieldName').Value := { Some calculated value }
end;

    or this way:

procedure TDataModule1.OldDataSetOnCalcFields(DataSet: TDataSet);
begin
  DataSet.Fields[?].Value := { Some calculated value }
end;

Note that the dataset to use comes in as a parameter.  (You may have
known this part already--I just didn't want to make any assumptions
about your experience level.)

Good luck,
Jon

At 01:14 AM 12/6/97, you wrote:

Quote
>Thanks for the answer ....

>What i need is like that :

>i wrote a component which gets a property - tdatasource.

>when is starts it kind of duplicates the the dataset (ttable or tquery).
>most of the duplication process works fine.

>the only problem is that calculated fields are not added to the fields
>property
>(fields ? or i forgot - i made it couple of months ago ...)

>i can get names of the calculated fields in runtime so i wrote a code that
>checks if
>the field is a calculated field and then call the original dataset's
>onclacfields event.

>but ... i want to do it directly for the new dataset.

>the reason i duplicate the dataset is that i do alot of "stuff" on the
>dataset and
>dont want the original dataset to change at all.

>if can add calculated fields to the new dataset than i can call the
>original dataset's
>oncalcfields event with the new dataset as the parameter.

>thats my problem ...

>if you can help (or cant ...) i would appreciate it ...

>thanks and bye !!