Determining changed fields in delta

Bit of a weird one this.

Inside my Business Processors’ AfterProcessChange handlers, I’m want to determine which fields/properties have changed for logging purposes.

Now I can hard-code this in each handler, using the strongly typed properties etc but I’m trying to find a generic way of iterating through all fields and detecting changes, so that I can use common logic for all tables/processors and also so they’ll cater for any future field changes.

Any ideas on how this could be done?

Hi,

  TDAAfterProcessChangeEvent = procedure(Sender: TDABusinessProcessor; aChange: TDADeltaChange; Processed: Boolean; var CanRemoveFromDelta: Boolean) of object;

you can enumerate values inside TDADeltaChange.
List of fields you can get from aChange.Delta

Ah ok, so the TDADeltaChange contains a list of variants with the old and new values and the parent TDADelta contains a list of fields and types.

I assume these two will always “marry up” so I can inspect the two variant lists in the TDADeltaChange to look for cases where old and new differ, then check the corresponding field index in TDADelta to find the details of the field?

Hi,

You are right.

we use this code in BP:

// skip generating field in case it wasn't changed
if lReducesDeltaMode and ROVariantsEqual(aChange.OldValues[i], aChange.NewValues[i]) then Continue;

Brilliant thanks, will give that a try.

In terms of determining the field that corresponds to the values in TDADeltaChange…

It seems I can use the LoggedFieldNames property of the delta to get the field name, is this correct? Can I rely on these fields always corresponding to the similarly indexed values in the change?

Also, it doesn’t look like I can get hold of the data type as the fFieldDataTypes array in TDADelta isn’t exposed anywhere I don’t think. Is this the case? If so then I’d have to try determining the datatype by the variant type held in the change values arrays, which isn’t ideal. Is there any way of determining the type of each field?

Hi,

yes

constructor TDADeltaChange.Create(aDelta: TDADelta;
  aRecID: Integer;
  aChangeType: TDAChangeType;
  aStatus: TDAChangeStatus = csPending;
  aMessage: string = '');
..
  SetLength(fOldValues, aDelta.LoggedFieldCount);
  SetLength(fNewValues, aDelta.LoggedFieldCount);
end;

You have LogicalName in Delta. also you have BP.Schema so you can easily detect correspondent dataset (TDADataset) in Schema.
You have Delta.LoggedFieldNames so you can easily get correspondent TDAField and check his datatype.

Cool thanks.

One last question…

In the case of SQL Server text and varchar(max) columns, the variant values appear to be a varArray of varByte (type $2011). How can I convert this to an (ansi)string?

Hi,

you can use uROBinaryHelpers.VariantToBytes and later transform TBytes to string with uROEncoding.AnsiBytesToString or uROEncoding.UTF16BytesToString.

Thanks will take a look