12. Adding custom strategies to table writers

We have seen here how table writers are used in EDW's ETL layer. A table writer does its work by embedding a strategy object, and EDW comes with a predefined set of strategies to perform the more common table writing operations, such as insert, update, delete, and merge. You might want to customize an existing table writer or create a completely new one. An example of the former type would be a Merge or Update table writer that only updates an existing record if the new one is newer according to a criteria (like a timestamp column). An example of the latter type would be a table writer that calls a stored procedure.

Adding a custom strategy involves creating a new class inherited from TEDWDBWriteStrategy or one of its descendants, and register it. In your new class, you'll override methods that perform the required operations and/or get the table writer's parameters in input. You'll need to override different methods in different cases. If your new strategy is inherited from the base TEDWDBWriteStrategy, you'll need to override at least BuildDBCommand and provide a custom SQL statement. If your new class needs to do something different than executing a SQL statement, you'll want to override InternalExecute, or DoBeforeExecute/DoAfterExecute.

You can also inherit your new strategy from one of the predefined strategies, in case you need only to customize the behaviour. The following code snippet defines a Merge strategy that, in case an existing record is found, will only upate it depending on a check on a timestamp column (to prevent older records from overwriting newer ones).

type
  TMergeNewerStrategy = class(TEDWMergeStrategy)
  protected
    function GetRecordExistsSelectList: string; override;
    procedure InternalPerformUpdate(const ADBParams,
      AExistingRecordValues: TEDWParamsEx); override;
  end;

...

function TMergeNewerStrategy.GetRecordExistsSelectList: string;
begin
  // We need to add the timestamp field that will be used to compare
  // the records in InternalPerformUpdate to the list of retrieved
  // fields, otherwise we won't be able to compare the values.
  Result := inherited GetRecordExistsSelectList + ', UPDATE_DATE_TIME';
end;

procedure TMergeNewerStrategy.InternalPerformUpdate(
  const ADBParams, AExistingRecordValues: TEDWParamsEx);
var
  LDateTime: TDateTime;
begin
  // Only update an existing record with a newer one.
  LDateTime := AExistingRecordValues.ParamByName('UPDATE_DATE_TIME').AsDateTime;
  if (LDateTime = 0) or (LDateTime > ADBParams.ParamByName('UPDATE_DATE_TIME').AsDateTime) then
    inherited;
end;

initialization
  EDWDBWriteStrategyRegistry.RegisterClass(TMergeNewerStrategy);

finalization
  EDWDBWriteStrategyRegistry.UnregisterClass(TMergeNewerStrategy);

Please see the EDW reference for more details, and use the existing strategy classes as examples.