As in the question's title, I argue with a colleague about how calculated fields should be used. From my knowledge, calculated fields are created at runtime as in the François's answer on the question Adding a calculated field to a Query at run time. On the same question there is another answer, from sabri.arslan which suggest to change an existing field to a calculated one(code bellow)
var
initing:boolean;
procedure TSampleForm.dsSampleAfterOpen(
DataSet: TDataSet);
var
i:integer;
dmp:tfield;
begin
if not initing then
try
initing:=true;
dataset.active:=false;
dataset.FieldDefs.Update;
for i:=0 to dataset.FieldDefs.Count-1 do
begin
dmp:=DataSet.FieldDefs.Items[i].FieldClass.Create(self);
dmp.FieldName:=DataSet.FieldDefs.Items[i].DisplayName;
dmp.DataSet:=dataset;
if (dmp.fieldname='txtState') or (dmp.FieldName='txtOldState') then
begin
dmp.Calculated:=true;
dmp.DisplayWidth:=255;
dmp.size:=255;
end;
end;
dataset.active:=true;
finally
initing:=false;
end;
end;
procedure TSampleForm.dsSampleAfterClose(
DataSet: TDataSet);
var
i:integer;
dmp:TField;
begin
if not initing then
begin
for i:=DataSet.FieldCount-1 downto 0 do
begin
dmp:=pointer(DataSet.Fields.Fields[i]);
DataSet.Fields.Fields[i].DataSet:=nil;
freeandnil(dmp);
end;
DataSet.FieldDefs.Clear;
end;
end;
procedure TSampleForm.dsSampleCalcFields(
DataSet: TDataSet);
var
tmpdurum,tmpOldDurum:integer;
begin
if not initing then
begin
tmpDurum := dataset.FieldByName( 'state' ).AsInteger;
tmpOldDurum:= dataset.FieldByName( 'oldstate' ).AsInteger;
dataset.FieldByName( 'txtState' ).AsString := State2Text(tmpDurum);
dataset.FieldByName( 'txtOldState' ).AsString := State2Text(tmpOldDurum);
end;
end;
procedure TSampleForm.btnOpenClick(Sender: TObject);
begin
if dsSample.Active then
dsSample.Close;
dsSample.SQL.text:='select id,state,oldstate,"" as txtState,"" as txtOldState from states where active=1';
dsSample.Open;
end;
I believe that this change leads to an unknown behavior of the specified TField. It is safe to change a dataset field to a calculated one on the runtime? What kind of issues can this generate?
LE: This is a question. Its purpose it is to demonstrate good practice on adding a calculated field on a dataset at runtime. And, yes adding a calculated field at runtime is bad design.
LE2: This is only an example for 'do not this in this way'. As an argument I asked what is the behavior of the field in discussion after doing this. How that field will act?
No, it´s not a good practice. The simple fact that the code is complex suggests that such a practice should be avoided. Someone already referenced the KISS principle and I agree with that.
Particularly, the simple fact that the dataset has to be opened twice is enough to make me to dislike this practice.
In addition, changing the field´s nature from data to calculated will change the way the dataset organizes the fields in its internal record representation (what the dataset calls a record buffer). Such a representation may be very different from one dataset implementation to another. Since the question didn´t identify a particular dataset, the changes in behavior are (in general):
However, a certain dataset implementation my present some other consequences, depending on its purpose and features.