Error inside TObjectDataSet with read only property

Issue #389 resolved
Zane Duffield created an issue

The implementation of TObjectDataSet has a slight issue with read only properties.

When the following conditions are satisfied

  1. The type inside the ODS has at least two published properties, with the read only property not last
  2. The ODS has declared the fields in the dfm
  3. The ODS has at least one row
  4. The ODS is linked to a DataSource
  5. Some form component adds a DataLink to the DataSource which attempts to read the value of a field corresponding to a property published after the read only one

Then TObjectDataSet.InitRttiPropertiesFromItemType will set field.ReadOnly := True which fires the DataLink which attempts to read the property before InitRttiPropertiesFromItemType has finished initializing the fields. This results in the exception “Property … not found”.

See my attached project for a working example.

My suggested fix is pretty simple, basically just delay the setting of ReadOnly until fProperties has been fully initialized.

procedure TObjectDataSet.InitRttiPropertiesFromItemType(AItemTypeInfo: PTypeInfo);
var
  itemType: TRttiType;
  prop: TRttiProperty;
  field: TField;
  readOnlyFields: TArray<TField>;
begin
  if AItemTypeInfo = nil then
    Exit;

  fProperties.Clear;

  itemType := TType.GetType(AItemTypeInfo);
  for prop in itemType.GetProperties do
  begin
    if not (prop.Visibility in [mvPublic, mvPublished]) then
      Continue;

    if Fields.Count > 0 then
    begin
      field := Fields.FindField(prop.Name);
      if Assigned(field) and (field.FieldKind = fkData) then
      begin
        fProperties.Add(prop);
        if not prop.IsWritable then
          // Delay setting of field property to prevent event handlers from accessing fields in a partially-initialized state.
          System.Insert(field, readOnlyFields, Length(readOnlyFields));
      end;
      Continue;
    end;

    if Assigned(fColumnAttributeClass) then
    begin
      if prop.HasCustomAttribute(fColumnAttributeClass) then
        fProperties.Add(prop);
    end
    else
      if prop.Visibility = mvPublished then
        fProperties.Add(prop);
  end;

  for field in readOnlyFields do
    field.ReadOnly := True;
end;

Comments (2)

  1. Stefan Glienke repo owner

    Thanks for reporting.

    However I cannot reproduce this with 2.0 (develop) and the code you posted looks different from the code in develop, thus I assume you are reporting this against 1.2.x (you could have selected the version when reporting to leave no doubt).

    I assume the added DisableControls/EnableControls in develop is what fixes this - so probably this is kind of a duplicate of #314

  2. Zane Duffield reporter

    Thanks Stefan, yes this does look like a duplicate of #314 and I was reporting this against 1.2.x (sorry for missing the version in the report).

  3. Log in to comment