Pass Generic Record in an array of const

Is it possible, in any way, to pass a Generic Record in an array of const argument to a function call ?

I would like to use the Nullable record from Allen Bauer in a kind of home made ORM using "Plain Old Delphi Objects" to map database rows :

type
  Nullable = record
    ...
  end;

  TMyTableObject = class(TDbOject)
  private
    FId: Integer;
    FOptionalField: Nullable;
  protected
    procedure InternalSave; override;
  public
    property Id: Integer read FId write SetId;
    property OptionalField: Nullable read FOptionalField write SetOptionalField;
  end;

  ...

  implementation

  procedure TMyTableObject.InternalSave;
  begin
    { FDbController is declared and managed in TDbObject, it contains fonction to run queries
      on the database }

    FDbController.Execute(
      'update or insert into MY_TABLE(TABLE_ID, OPTIONAL_FIELD) ' +
      'values (?, ?) ' + 
      'matching(TABLE_ID) returning TABLE_ID', [FId, FOptionalField],
      procedure (Fields: TSQLResult)
      begin
        FId := Fields.AsInteger[0];
      end;
    end;      
  end;

The above code results in an error : "E2250 : no overriden version of the "Execute" function can be called with these arguments" (translated from French : E2250 Aucune version surchargée de 'Execute' ne peut être appelée avec ces arguments)

I could explicitly convert FOptionalField to string or anything else since Nullable overrides ad-hoc operators but I really have to know if the Nullable has a value or not until I map the array of const into the Params field of the database query object :

procedure TDbContext.MapParams(Q: TUIBQuery; Params: TConstArray);
const
  BOOL_STR: array[Boolean] of string = ('F', 'V');
var
  i: Integer;
begin
  for i := 0 to High(Params) do
    case Params[i].VType of
      vtInteger :      Q.Params.AsInteger[i]       := Params[i].VInteger;
      vtInt64   :      Q.Params.AsInt64[i]         := Params[i].VInt64^;
      vtBoolean :      Q.Params.AsString[i]        := BOOL_STR[Params[i].VBoolean];
      vtChar    :      Q.Params.AsAnsiString[i]    := Params[i].VChar;
      vtWideChar:      Q.Params.AsString[i]        := Params[i].VWideChar;
      vtExtended:      Q.Params.AsDouble[i]        := Params[i].VExtended^;
      vtCurrency:      Q.Params.AsCurrency[i]      := Params[i].VCurrency^;
      vtString  :      Q.Params.AsString[i]        := string(Params[i].VString^);
      vtPChar   :      Q.Params.AsAnsiString[i]    := Params[i].VPChar^;
      vtAnsiString:    Q.Params.AsAnsiString[i]    := AnsiString(Params[i].VAnsiString);
      vtWideString:    Q.Params.AsUnicodeString[i] := PWideChar(Params[i].VWideString);
      vtVariant   :    Q.Params.AsVariant[i]       := Params[i].VVariant^;
      vtUnicodeString: Q.Params.AsUnicodeString[i] := string(Params[i].VUnicodeString);
      vtPointer :
      begin
        if Params[i].VPointer = nil then
          Q.Params.IsNull[i] := True
        else
          Assert(False, 'not nil pointer is not supported');
      end
    else
      Assert(False, 'not supported');
    end;
end;

Do you have any idea on how to make this kind of construct possible ? I find a way by adding an explicit cast operator override to Variant in Nullable using RTTI but that's a bit tricky because it needs an explicit cast to Variant in the array of const call :

class operator Nullable.Explicit(Value: Nullable): Variant;
begin
  if Value.HasValue then
    Result := TValue.From(Value.Value).AsVariant
  else
    Result := Null;
end;

...

    FDbController.Execute(
      'update or insert into MY_TABLE(TABLE_ID, OPTIONAL_FIELD) ' +
      'values (?, ?) ' + 
      'matching(TABLE_ID) returning TABLE_ID', [FId, Variant(FOptionalField)],
      procedure (Fields: TSQLResult)
      begin
        FId := Fields.AsInteger[0];
      end;
    end;  

8
задан ZeDalaye 10 May 2011 в 08:48
поделиться