srayner
srayner

Reputation: 1837

How to stop TField.Origin from getting reset

I use the TField.origin property to dynamically build a where clause for SQL queries.

So if I have a query such as;

select
  p.firstname,
  p.lastname,
  g.description
from
  people p
  inner join groups g

I can set the origin of the firstname field to;

FirstNameField.origin = 'p.firstname';

Then use this in the where clause of dynamic queries such as;

SQLWhere = 'where ' + FirstNameField.origin + ' = ''' + MyValue + ''' ';

(obviously i have additional code to prevent against SQL injection).

I do this all the time and it works great. However when trying to track down a bug, I noticed I have one dataset that keeps reseting the value of the origin for example back to;

people.firstname

instead of;

p.firstname

I tracked it down to when the dataset is closed and then reopened. However I do this all the time, so I can't understand why one dataset has different behaviour.

My question is how can I prevent the origin value from getting reset?

Upvotes: 1

Views: 230

Answers (1)

MartynA
MartynA

Reputation: 30715

The code below is from D7's IBCustomDataSet unit (the code is more complex in later XEx versions).

It's this code which sets the Origin property of an IBX TField.

TIBCustomDataSet.CreateFields will get called when the dataset calls its InternalOpen method if its FDefaultFields field is True. It will be True if on entry to InternalOpen the FieldCount of the dataset is zero. FieldCount will be zero if no fields have been created in advance, either in user-code or in the IDE using the Fields editor on the dataset. InternalOpen is called by TDataSet.Open via its OpenCursor method.

So the way to avoid 'CreateFields' being executed and the dataset fields' Origin properties being reset as a consequence is to use either of these methods (IDE or user code) to create the fields prior to opening the dataset. In other words, if you set the Origin property by either of these methods, that should avoid it getting reset.

procedure TIBCustomDataSet.CreateFields;
var
  FieldAliasName, RelationName : String;
  i : Integer;
  f : TField;
begin
  inherited;
  for i := 0 to FQSelect.Current.Count - 1 do
    with FQSelect.Current[i].Data^ do
    begin
      { Get the field name }
      SetString(FieldAliasName, aliasname, aliasname_length);
      SetString(RelationName, relname, relname_length);
      f := FindField(FieldAliasname);
      if Assigned(f) then
      begin
        if (RelationName <> '') and (FieldAliasName <> '') then
          f.Origin := RelationName + '.' + FieldAliasName;
      end;
    end;
end;

Update The implementation of TIBCustomDataSet.InternalOpen was evidently changed between XE4 and XE6 so that CreateFields is now called unconditionally (i.e. regardless of whether DefaultFields is True). Therefore, having already-existing TFields will not avoid CreateFields being called and therefore the Origin properties being reset.

Upvotes: 3

Related Questions