Carefully review and enhance the code below to perform the bidirectional binding between the TComponent property changes and its corresponding TQryRecInfo descendant property.
I need this code to operate to perform bidirectional update, following some rules:
if the TQryRecInfo descendant property is mapped to a TEdit, then this property maps to the TEdit.Text
if the TQryRecInfo descendant property is mapped to a TLabel, then this property maps to the TLabel.Caption
if the TQryRecInfo descendant property is mapped to a TDatePicker, then this property maps to the TDatePicker.Date
and so on...
When the TQryRecInfo descendant property is not a string, but it should map to a string TComponent property, then use GetFormattedText to convert to its string representation
------------------------------------

unit Main;

interface

uses
  Vcl.Forms, System.Classes, Vcl.Controls, Vcl.StdCtrls, ORM_utils, interposer_class, SysUtils, Dialogs, formgerenc_Classes;

type
  TMainForm = class(TForm)
    EditUserName: TEdit;
    EditPassword: TEdit;
    LabelUserName: TLabel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FQueryRec1: TEmployeeProject;
    FQueryRec2: TEmployeeProject;
    procedure SetupComponents;
  public
    function RetrieveComponent(ORMRec: TQryRecInfo; FieldName: string): TComponent;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.Button1Click(Sender: TObject);
begin
 var MyComp:= RetrieveComponent(FQueryRec2, 'password');
 if Assigned(MyComp) then
 showmessage(MyComp.Name)
 else showmessage('Componente não encontrado');
end;

procedure TMainForm.Button2Click(Sender: TObject);
begin
 UnRegisterORMComponent(EditPassword);

 // Automatically register components where the Hint matches a field in FQueryRec1
 RegisterComponentsByHint(FQueryRec2);
 begin
 var MyComp:= RetrieveComponent(FQueryRec2, 'employeeNAme');
 if Assigned(MyComp) then
 showmessage(MyComp.Name)
 else showmessage('Componente employeeName não encontrado');
 end;

 begin;
 var MyComp:= RetrieveComponent(FQueryRec2, 'employeeId');
 if Assigned(MyComp) then
 showmessage(MyComp.Name)
 else showmessage('Componente EmployeeID não encontrado');
 end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  // Initialize the ORM record instances
  FQueryRec1 := TEmployeeProject.Create;
  FQueryRec2 := TEmployeeProject.Create;

  // Setup components with ORM properties and register them
  SetupComponents;
end;

procedure TMainForm.SetupComponents;
begin
  // Register EditUserName with ORMRec and FieldName
  RegisterORMComponent(EditUserName, FQueryRec1, 'UserName');

  // Register EditPassword with ORMRec and FieldName
  RegisterORMComponent(EditPassword, FQueryRec2, 'Password');

  // Register LabelUserName with ORMRec and FieldName
  RegisterORMComponent(LabelUserName, FQueryRec1, 'UserLabel');
end;

function TMainForm.RetrieveComponent(ORMRec: TQryRecInfo; FieldName: string): TComponent;
begin
  // Find and return the component based on ORMRec and FieldName
  Result := FindComponentByORMRec(ORMRec, FieldName);
end;

end.

------------------------------------

unit formgerenc_Classes;

{$TYPEINFO ON}

interface

uses
  orm_utils, pixel_classes, ORM_CustomAttributes;

type
  TEmployeeProject = class(TQryRecInfo)
  private
    [Table('employees'), PrimaryKey, RefColumn('emp_id')]
    _EmployeeID: TNullable<Integer>;
    [Table('employees'), PrimaryKey, RefColumn('dept_id')]
    _DepartmentID: TNullable<Integer>;
    [Table('employees'), RefColumn('emp_name')]
    _EmployeeName: TNullable<String>;
    [Table('projects'), PrimaryKey, RefColumn('proj_id')]
    _ProjectID: TNullable<Integer>;
    [Table('projects'), RefColumn('proj_name')]
    _ProjectName: TNullable<String>;
    [Table('projects'), RefColumn('proj_budget'), FmtProp(tiMoney)]
    _ProjectBudget: TNullable<Currency>;


    [FmtProp(tiMoney)]
    _BudgetLimit: Currency;

    _Age: Integer;
    _Older: Boolean;


    [Table('projects'), RefColumn('proj_date'), FmtProp(tiDate)]
    _ProjectDate: TNullable<TDateTime>;
    [Table('projects'), RefColumn('proj_starttime'), FmtProp(tiDateTime)]
    _ProjectStartMoment: TNullable<TDateTime>;

  published
    property EmployeeID: TNullable<Integer> index 0 read _EmployeeID write SetInfoNullableInteger;
    property DepartmentID: TNullable<Integer> index 1 read _DepartmentID write SetInfoNullableInteger;
    property EmployeeName: TNullable<String> index 2 read _EmployeeName write SetInfoNullableString;
    property ProjectID: TNullable<Integer> index 3 read _ProjectID write SetInfoNullableInteger;
    property ProjectName: TNullable<String> index 4 read _ProjectName write SetInfoNullableString;
    property ProjectBudget: TNullable<Currency> index 5 read _ProjectBudget write SetInfoNullableCurrency;
    property BudgetLimit: Currency index 6 read _BudgetLimit write SetInfoCurrency;
    property Age: Integer index 7 read _Age write SetInfoInteger;
    property Older: Boolean index 8 read _Older write SetInfoBoolean;
    property ProjectDate: TNullable<TDateTime> index 9 read _ProjectDate write SetInfoNullableDateTime;
    property ProjectStartMoment: TNullable<TDateTime> index 10 read _ProjectStartMoment write SetInfoNullableDateTime;
  end;

implementation

end.

------------------------------------

unit ORM_CustomAttributes;

{$TYPEINFO ON}

interface

uses
  System.SysUtils, System.Classes, System.Rtti;

type
  TFormatType = (tiString, tiInteger, tiDate, tiDateTime, tiMoney, tiFloat, tiBoolean, tiByteArray, tiNone);

  /// <summary>
  /// Attribute to specify the database table associated with a class or field.
  /// </summary>
  TableAttribute = class(TCustomAttribute)
  private
    FTableName: string;
  public
    constructor Create(const ATableName: string);
    property TableName: string read FTableName;
  end;

  /// <summary>
  /// Attribute to mark a field as a primary key.
  /// </summary>
  PrimaryKeyAttribute = class(TCustomAttribute)
  public
    constructor Create;
  end;

  /// <summary>
  /// Attribute to specify the database column associated with a field.
  /// </summary>
  RefColumnAttribute = class(TCustomAttribute)
  private
    FColumnName: string;
  public
    constructor Create(const AColumnName: string);
    property ColumnName: string read FColumnName;
  end;

  /// <summary>
  /// Attribute to specify the formatting of a field.
  /// </summary>
  FmtPropAttribute = class(TCustomAttribute)
  private
    FFormatType: TFormatType;
  public
    constructor Create(AFormatType: TFormatType);
    property FormatType: TFormatType read FFormatType;
  end;

  /// <summary>
  /// Attribute to specify the column index of a property in a TStringGrid.
  /// </summary>
  GridColumnAttribute = class(TCustomAttribute)
  private
    FColumnIndex: Integer;
  public
    constructor Create(AColumnIndex: Integer);
    property ColumnIndex: Integer read FColumnIndex;
  end;

  /// <summary>
  /// Attribute to specify the TComponent a property is mapped to.
  /// </summary>
  ComponentMappingAttribute = class(TCustomAttribute)
  private
    FComponentName: string;
  public
    constructor Create(const AComponentName: string);
    property ComponentName: string read FComponentName;
  end;

implementation

{ TableAttribute }

constructor TableAttribute.Create(const ATableName: string);
begin
  inherited Create;
  FTableName := ATableName;
end;

{ RefColumnAttribute }

constructor RefColumnAttribute.Create(const AColumnName: string);
begin
  inherited Create;
  FColumnName := AColumnName;
end;

{ PrimaryKeyAttribute }

constructor PrimaryKeyAttribute.Create;
begin
  inherited Create;
end;

{ FmtPropAttribute }

constructor FmtPropAttribute.Create(AFormatType: TFormatType);
begin
  inherited Create;
  FFormatType := AFormatType;
end;

{ GridColumnAttribute }

constructor GridColumnAttribute.Create(AColumnIndex: Integer);
begin
  inherited Create;
  FColumnIndex := AColumnIndex;
end;

{ ComponentMappingAttribute }

constructor ComponentMappingAttribute.Create(const AComponentName: string);
begin
  inherited Create;
  FComponentName := AComponentName;
end;

end.

------------------------------------

unit pixel_classes;

interface

uses
 System.SysUtils, Rtti, TypInfo;

{$TYPEINFO ON}

type
 TZString = type string;

type
  TNullValue = record
  end;

  TNullable<T{: record}> = record
  public
    Value: T;
    HasValue: Boolean;

    class operator Implicit(const AValue: T): TNullable<T>;
    class operator Implicit(const AValue: TNullable<T>): T;
    class operator Implicit(const AValue: TNullValue): TNullable<T>;
    class operator Explicit(const AValue: T): TNullable<T>;

    // add these...
    class operator Equal(const A: TNullable<T>; const B: TNullValue): Boolean;
    class operator NotEqual(const A: TNullable<T>; const B: TNullValue): Boolean;
  end;

var NullValue: TNullValue;

implementation

class operator TNullable<T>.Implicit(const AValue: T): TNullable<T>;
begin
  Result.Value := AValue;
  Result.HasValue := True;
end;

class operator TNullable<T>.Implicit(const AValue: TNullable<T>): T;
begin
  if AValue.HasValue then
    Result := AValue.Value
  else
    Result := Default(T); // or raise an exception
end;

class operator TNullable<T>.Implicit(const AValue: TNullValue): TNullable<T>;
begin
  Result.Value := Default(T);
  Result.HasValue := False;
end;

class operator TNullable<T>.Explicit(const AValue: T): TNullable<T>;
begin
  Result.Value := AValue;
  Result.HasValue := True;
end;

class operator TNullable<T>.Equal(const A: TNullable<T>; const B: TNullValue): Boolean;
begin
  Result := not A.HasValue;
end;

class operator TNullable<T>.NotEqual(const A: TNullable<T>; const B: TNullValue): Boolean;
begin
  Result := A.HasValue;
end;

end.

------------------------------------

unit orm_utils;

interface

uses
  System.SysUtils,
  System.Classes,
  System.Generics.Collections,
  System.Rtti,
  System.TypInfo,
  Data.DB,
  Uni,
  pixel_classes,
  orm_customattributes;

type
  EORMUtilsException = class(Exception);

  /// <summary>
  /// Base class for query record information
  /// Use descendants of this class to represent specific database records.
  /// </summary>
  TQryRecInfo = class
  private
    FDirtyFields: TDictionary<string, Boolean>;
    FPreviousValues: TDictionary<string, TValue>;
    procedure SetInfo(Index: Integer; const Value: TValue);
  public
    constructor Create;
    destructor Destroy; override;

    // Methods to set nullable fields
    procedure SetInfoNullableString(Index: Integer; const Value: TNullable<string>);
    procedure SetInfoNullableInteger(Index: Integer; const Value: TNullable<Integer>);
    procedure SetInfoNullableInt64(Index: Integer; const Value: TNullable<Int64>);
    procedure SetInfoNullableExtended(Index: Integer; const Value: TNullable<Extended>);
    procedure SetInfoNullableCurrency(Index: Integer; const Value: TNullable<Currency>);
    procedure SetInfoNullableDateTime(Index: Integer; const Value: TNullable<TDateTime>);
    procedure SetInfoNullableBoolean(Index: Integer; const Value: TNullable<Boolean>);
    procedure SetInfoNullableVariant(Index: Integer; const Value: TNullable<Variant>);

    // Methods to set non-nullable simple types
    procedure SetInfoCurrency(Index: Integer; const Value: Currency);
    procedure SetInfoString(Index: Integer; const Value: string);
    procedure SetInfoInteger(Index: Integer; const Value: Integer);
    procedure SetInfoInt64(Index: Integer; const Value: Int64);
    procedure SetInfoExtended(Index: Integer; const Value: Extended);
    procedure SetInfoDateTime(Index: Integer; const Value: TDateTime);
    procedure SetInfoBoolean(Index: Integer; const Value: Boolean);
    procedure SetInfoVariant(Index: Integer; const Value: Variant);

    // Methods to handle dirty fields
    function IsFieldDirty(const FieldName: string): Boolean;
    procedure ClearDirtyFlags;
    property DirtyFields: TDictionary<string, Boolean> read FDirtyFields;

    // Methods to handle previous values
    function GetPreviousValue(const FieldName: string): TValue;
    procedure ClearPreviousValues;
    property PreviousValues: TDictionary<string, TValue> read FPreviousValues;

    /// <summary>
    /// Retrieves the formatted text for a given field based on the FmtProp attribute.
    /// </summary>
    function GetFormattedText(const FieldName: string): string;

    /// <summary>
    /// Fetches data for this record from the database based on the provided SQL.
    /// </summary>
    procedure Fetch(DBConn: TUniConnection; const QryTxt: string);
  end;

  /// <summary>
  /// Generic class to handle arrays of TQryRecInfo descendants.
  /// </summary>
  TQryRecArray<T: class, constructor> = class
  private
    FQryRecInfoList: TObjectList<T>;
    FFilterSQL: string;
    FDBConn: TUniConnection;
    function GetCount: Integer;
  public
    constructor Create;
    destructor Destroy; override;

    /// <summary>
    /// Fetches all records based on the provided SQL text and populates the array.
    /// </summary>
    /// <param name="QryTxt">The base SQL query text.</param>
    procedure FetchAllInstance(DBConn: TUniConnection; const QryTxt: string);

    /// <summary>
    /// Clears any SQL filters applied.
    /// </summary>
    procedure ClearFilter;

    /// <summary>
    /// Accesses a record at the specified index.
    /// </summary>
    /// <param name="Index">The zero-based index of the record.</param>
    /// <returns>The record at the specified index.</returns>
    function Rec(Index: Integer): T;

    /// <summary>
    /// Number of records in the array.
    /// </summary>
    property RecCount: Integer read GetCount;

    /// <summary>
    /// Database connection used for fetching records.
    /// </summary>
    property DBConn: TUniConnection read FDBConn write FDBConn;

    /// <summary>
    /// Additional SQL filter to apply to the query.
    /// </summary>
    property SQLFilter: string read FFilterSQL write FFilterSQL;

    /// <summary>
    /// Provides support for for-in loops by returning an enumerator.
    /// </summary>
    function GetEnumerator: TEnumerator<T>;

    /// <summary>
    /// Factory method to create and fetch records in a single step.
    /// </summary>
    /// <param name="DBConn">Database connection.</param>
    /// <param name="QryTxt">SQL query text.</param>
    /// <returns>Populated instance of TQryRecArray<T>.</returns>
    class function FetchAll(DBConn: TUniConnection; const QryTxt: string): TQryRecArray<T>; static;
  end;

  // Example descendant of TQryRecInfo (You can create your own)
  TDynRec = class(TQryRecInfo)
    // Define additional properties as needed
  end;

implementation

uses
  System.Variants,
  StrUtils,
  pixel_utils; // Ensure this unit is in your project and properly implemented

{ TQryRecInfo }

constructor TQryRecInfo.Create;
begin
  inherited Create;
  FDirtyFields := TDictionary<string, Boolean>.Create;
  FPreviousValues := TDictionary<string, TValue>.Create;
end;

destructor TQryRecInfo.Destroy;
begin
  FDirtyFields.Free;
  FPreviousValues.Free;
  inherited;
end;

procedure TQryRecInfo.ClearDirtyFlags;
begin
  FDirtyFields.Clear;
end;

procedure TQryRecInfo.ClearPreviousValues;
begin
  FPreviousValues.Clear;
end;

function TQryRecInfo.IsFieldDirty(const FieldName: string): Boolean;
begin
  Result := FDirtyFields.ContainsKey(FieldName) and FDirtyFields[FieldName];
end;

function TQryRecInfo.GetPreviousValue(const FieldName: string): TValue;
begin
  if not FPreviousValues.TryGetValue(FieldName, Result) then
    raise EORMUtilsException.CreateFmt('No previous value found for field "%s".', [FieldName]);
end;

function FormataInfo(info: Variant; tipo: TFormatType): string;
begin
  if VarIsNull(info) or VarIsEmpty(info) then
    Exit('');

  case tipo of
    tiString:
      Result := VarToStr(info);
    tiInteger:
      Result := IntToStr(Integer(info));
    tiMoney:
      Result := FormatFloat(FMT_MONEY, Currency(info));
    tiFloat:
      Result := FloatToStr(info);
    tiDate:
      if VarIsType(info, [varDate, varDouble]) then
      begin
        if VarToDateTime(info) < EncodeDate(1900, 1, 1) then
          Result := ''
        else
          Result := FormatDateTime('dd/mm/yyyy', VarToDateTime(info));
      end
      else
        raise EORMUtilsException.CreateFmt('FormataInfo: Cannot treat information [%s] as tiDate.', [VarToStr(info)]);
    tiDateTime:
      if VarIsType(info, [varDate, varDouble]) then
      begin
        if VarToDateTime(info) = 0 then
          Result := ''
        else
          Result := FormatDateTime('dd/mm/yyyy hh:mm:ss', VarToDateTime(info));
      end
      else
        raise EORMUtilsException.CreateFmt('FormataInfo: Cannot treat information [%s] as tiDateTime.', [VarToStr(info)]);
    tiBoolean:
      Result := IfThen(Boolean(info), 'S', 'N');
    tiByteArray:
      Result := ByteArrayToHex(info);
    tiNone:
      Result := '';
  else
    raise EORMUtilsException.CreateFmt('FormataInfo: Format type [%s] not recognized.', [GetEnumName(TypeInfo(TFormatType), Integer(tipo))]);
  end;
end;

function TQryRecInfo.GetFormattedText(const FieldName: string): string;
var
  Ctx: TRttiContext;
  RttiType: TRttiType;
  Prop: TRttiProperty;
  Field: TRttiField;
  Value: TValue;
  FmtType: TFormatType;
  UnderlyingType: TRttiType;
  HasValueField: TRttiField;
  ValueField: TRttiField;
  HasValue: Boolean;
  ActualValue: TValue;
  Attr: TCustomAttribute;
  FmtAttr: FmtPropAttribute;
begin
  Result := '';
  Ctx := TRttiContext.Create;
  try
    RttiType := Ctx.GetType(Self.ClassType);

    // Find the property by name
    Prop := RttiType.GetProperty(FieldName);
    if not Assigned(Prop) then
      raise EORMUtilsException.CreateFmt('Property "%s" not found.', [FieldName]);

    // Get the value of the property
    Value := Prop.GetValue(Self);
    FmtType := tiNone;

    // Check for FmtProp attribute on the property
    for Attr in Prop.GetAttributes do
    begin
      if Attr is FmtPropAttribute then
      begin
        FmtAttr := FmtPropAttribute(Attr);
        FmtType := FmtAttr.FormatType;
        Break;
      end;
    end;

    // If not found on property, check on the corresponding field
    if FmtType = tiNone then
    begin
      Field := RttiType.GetField('_' + FieldName);
      if Assigned(Field) then
      begin
        for Attr in Field.GetAttributes do
        begin
          if Attr is FmtPropAttribute then
          begin
            FmtAttr := FmtPropAttribute(Attr);
            FmtType := FmtAttr.FormatType;
            Break;
          end;
        end;
      end;
    end;

    // Determine default FmtType based on property type if not set by attribute
    if FmtType = tiNone then
    begin
      UnderlyingType := Prop.PropertyType;

      // Handle TNullable<T>
      if UnderlyingType.TypeKind = tkRecord then
      begin
        ValueField := UnderlyingType.GetField('Value');
        if Assigned(ValueField) then
          UnderlyingType := ValueField.FieldType;
      end;

      case UnderlyingType.TypeKind of
        tkInteger, tkInt64:
          FmtType := tiInteger;
        tkFloat:
          if UnderlyingType.Handle = TypeInfo(TDateTime) then
            FmtType := tiDateTime
          else
            FmtType := tiFloat;
        tkString, tkLString, tkWString, tkUString:
          FmtType := tiString;
        tkEnumeration:
          if UnderlyingType.Handle = TypeInfo(Boolean) then
            FmtType := tiBoolean
          else
            FmtType := tiString;
        tkVariant:
          FmtType := tiString;
      else
        FmtType := tiNone;
      end;
    end;

    // Extract actual value from TNullable<T> if necessary
    if Value.Kind = tkRecord then
    begin
      // Assuming TNullable<T> has 'HasValue' and 'Value' fields
      UnderlyingType := Prop.PropertyType;
      HasValueField := UnderlyingType.GetField('HasValue');
      ValueField := UnderlyingType.GetField('Value');

      if Assigned(HasValueField) and Assigned(ValueField) then
      begin
        HasValue := HasValueField.GetValue(Value.GetReferenceToRawData).AsBoolean;
        if HasValue then
        begin
          ActualValue := ValueField.GetValue(Value.GetReferenceToRawData);
          // Format the actual value
          Result := FormataInfo(ActualValue.AsVariant, FmtType);
        end
        else
          Result := '';
      end
      else
      begin
        // Not TNullable<T>, handle value directly
        if not Value.IsEmpty then
          Result := FormataInfo(Value.AsVariant, FmtType)
        else
          Result := '';
      end;
    end
    else
    begin
      // Not a record, handle value directly
      if not Value.IsEmpty then
        Result := FormataInfo(Value.AsVariant, FmtType)
      else
        Result := '';
    end;
  finally
    // No need to free TRttiContext as it's a record
  end;
end;

procedure TQryRecInfo.Fetch(DBConn: TUniConnection; const QryTxt: string);
var
  qr: TUniQuery;
  Ctx: TRttiContext;
  ObjType: TRttiType;
  Prop: TRttiProperty;
  Field: TField;
  ORMFieldName: string;
begin
  if not Assigned(DBConn) or Trim(QryTxt).IsEmpty then
    Exit;

  qr := TUniQuery.Create(nil);
  try
    qr.Connection := DBConn;
    qr.SpecificOptions.Values['FetchAll'] := 'True';
    qr.SpecificOptions.Values['CreateConnection'] := 'False';
    qr.SQL.Text := QryTxt;
    qr.Open;

    if qr.RecordCount > 0 then
    begin
      Ctx := TRttiContext.Create;
      try
        ObjType := Ctx.GetType(Self.ClassType);

        for Prop in ObjType.GetProperties do
        begin
          if not Prop.IsWritable then
            Continue;

          // Attempt to find the corresponding field in the query
          Field := qr.FindField(Prop.Name);
          if not Assigned(Field) then
            Continue; // Field not found, skip

          ORMFieldName := '_' + Prop.Name;
          // Handle TNullable<T> types
          if Prop.PropertyType.TypeKind = tkRecord then
          begin
            // Expecting TNullable<T>
            // Attempt to find the backing field for the nullable property
            if ObjType.GetField(ORMFieldName) = nil then
              Continue; // Backing field not found, skip

            if Prop.PropertyType.Name.StartsWith('TNullable<') then
            begin
              // Use RTTI to determine the generic type parameter
              if Field.IsNull then
                ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<string>>(NullValue))
              else
              begin
                if Prop.PropertyType.Name = 'TNullable<System.string>' then
                  ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<string>>(Field.AsString))
                else if Prop.PropertyType.Name = 'TNullable<System.Integer>' then
                  ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<Integer>>(Field.AsInteger))
                else if Prop.PropertyType.Name = 'TNullable<System.Int64>' then
                  ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<Int64>>(Field.AsLargeInt))
                else if Prop.PropertyType.Name = 'TNullable<System.Extended>' then
                  ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<Extended>>(Field.AsFloat))
                else if Prop.PropertyType.Name = 'TNullable<System.Currency>' then
                  ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<Currency>>(Field.AsCurrency))
                else if Prop.PropertyType.Name = 'TNullable<System.TDateTime>' then
                  ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<TDateTime>>(Field.AsDateTime))
                else if Prop.PropertyType.Name = 'TNullable<System.Boolean>' then
                  ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<Boolean>>(Field.AsBoolean))
                else if Prop.PropertyType.Name = 'TNullable<System.Variant>' then
                  ObjType.GetField(ORMFieldName).SetValue(Self, TValue.From<TNullable<Variant>>(Field.Value))
                else
                  raise EORMUtilsException.CreateFmt('Unsupported TNullable type: %s', [Prop.PropertyType.Name]);
              end;
            end
            else
              raise EORMUtilsException.CreateFmt('Unsupported record type: %s', [Prop.PropertyType.Name]);
          end
          else
          begin
            // Handle non-nullable types
            case Prop.PropertyType.TypeKind of
              tkString, tkLString, tkWString, tkUString:
                ObjType.GetField(ORMFieldName).SetValue(Self, Field.AsString);
              tkInteger:
                ObjType.GetField(ORMFieldName).SetValue(Self, Field.AsInteger);
              tkInt64:
                ObjType.GetField(ORMFieldName).SetValue(Self, Field.AsLargeInt);
              tkFloat:
                if Prop.PropertyType.Handle = TypeInfo(Currency) then
                  ObjType.GetField(ORMFieldName).SetValue(Self, Field.AsCurrency)
                else
                  ObjType.GetField(ORMFieldName).SetValue(Self, Field.AsFloat);
              tkVariant:
                ObjType.GetField(ORMFieldName).SetValue(Self, TValue.FromVariant(Field.AsVariant));
              tkEnumeration:
                if Prop.PropertyType.Handle = TypeInfo(Boolean) then
                  ObjType.GetField(ORMFieldName).SetValue(Self, Field.AsBoolean)
                else
                  raise EORMUtilsException.CreateFmt('Unsupported enumeration type: %s', [Prop.PropertyType.Name]);
            else
              // Add additional handling for other types if necessary
            end;
          end;
        end;
      finally
        // No need to free TRttiContext as it's a record
      end;
    end;
  finally
    qr.Free;
  end;
end;

procedure TQryRecInfo.SetInfo(Index: Integer; const Value: TValue);
var
  PropName: string;
  PropKind: TTypeKind;
  Ctx: TRttiContext;
  Prop: TRttiProperty;
  Field: TRttiField;
  OldValue: TValue;
begin
  // Retrieve property name and kind based on index
  // Assuming that the index corresponds to the property order
  Ctx := TRttiContext.Create;
  try
    Prop := Ctx.GetType(Self.ClassType).GetProperties()[Index];
    if not Assigned(Prop) then
      raise EORMUtilsException.CreateFmt('Error: The index "%d" does not correspond to any property in class "%s".', [Index, ClassName]);

    PropName := Prop.Name;
    PropKind := Prop.PropertyType.TypeKind;

    Field := Ctx.GetType(Self.ClassType).GetField('_' + PropName);
    if not Assigned(Field) then
      raise EORMUtilsException.CreateFmt('Error: Field "_%s" not found in class "%s".', [PropName, ClassName]);

    // If the field is not yet dirty, store the previous value
    if not FDirtyFields.ContainsKey(PropName) then
    begin
      OldValue := Field.GetValue(Self);
      FPreviousValues.AddOrSetValue(PropName, OldValue);
    end;

    // Set the new value
    Field.SetValue(Self, Value);

    // Mark the property as dirty
    FDirtyFields.AddOrSetValue(PropName, True);
  finally
    // No need to free TRttiContext as it's a record
  end;
end;

procedure TQryRecInfo.SetInfoCurrency(Index: Integer; const Value: Currency);
begin
  SetInfo(Index, TValue.From<Currency>(Value));
end;

procedure TQryRecInfo.SetInfoString(Index: Integer; const Value: string);
begin
  SetInfo(Index, TValue.From<string>(Value));
end;

procedure TQryRecInfo.SetInfoInteger(Index: Integer; const Value: Integer);
begin
  SetInfo(Index, TValue.From<Integer>(Value));
end;

procedure TQryRecInfo.SetInfoInt64(Index: Integer; const Value: Int64);
begin
  SetInfo(Index, TValue.From<Int64>(Value));
end;

procedure TQryRecInfo.SetInfoExtended(Index: Integer; const Value: Extended);
begin
  SetInfo(Index, TValue.From<Extended>(Value));
end;

procedure TQryRecInfo.SetInfoDateTime(Index: Integer; const Value: TDateTime);
begin
  SetInfo(Index, TValue.From<TDateTime>(Value));
end;

procedure TQryRecInfo.SetInfoBoolean(Index: Integer; const Value: Boolean);
begin
  SetInfo(Index, TValue.From<Boolean>(Value));
end;

procedure TQryRecInfo.SetInfoVariant(Index: Integer; const Value: Variant);
begin
  SetInfo(Index, TValue.From<Variant>(Value));
end;

procedure TQryRecInfo.SetInfoNullableBoolean(Index: Integer; const Value: TNullable<Boolean>);
begin
  SetInfo(Index, TValue.From<TNullable<Boolean>>(Value));
end;

procedure TQryRecInfo.SetInfoNullableCurrency(Index: Integer; const Value: TNullable<Currency>);
begin
  SetInfo(Index, TValue.From<TNullable<Currency>>(Value));
end;

procedure TQryRecInfo.SetInfoNullableDateTime(Index: Integer; const Value: TNullable<TDateTime>);
begin
  SetInfo(Index, TValue.From<TNullable<TDateTime>>(Value));
end;

procedure TQryRecInfo.SetInfoNullableExtended(Index: Integer; const Value: TNullable<Extended>);
begin
  SetInfo(Index, TValue.From<TNullable<Extended>>(Value));
end;

procedure TQryRecInfo.SetInfoNullableInteger(Index: Integer; const Value: TNullable<Integer>);
begin
  SetInfo(Index, TValue.From<TNullable<Integer>>(Value));
end;

procedure TQryRecInfo.SetInfoNullableInt64(Index: Integer; const Value: TNullable<Int64>);
begin
  SetInfo(Index, TValue.From<TNullable<Int64>>(Value));
end;

procedure TQryRecInfo.SetInfoNullableString(Index: Integer; const Value: TNullable<string>);
begin
  SetInfo(Index, TValue.From<TNullable<string>>(Value));
end;

procedure TQryRecInfo.SetInfoNullableVariant(Index: Integer; const Value: TNullable<Variant>);
begin
  SetInfo(Index, TValue.From<TNullable<Variant>>(Value));
end;

{ TQryRecArray<T> }

constructor TQryRecArray<T>.Create;
begin
  inherited Create;
  FQryRecInfoList := TObjectList<T>.Create(True); // Owns objects
end;

destructor TQryRecArray<T>.Destroy;
begin
  FQryRecInfoList.Free;
  inherited;
end;

procedure TQryRecArray<T>.ClearFilter;
begin
  FFilterSQL := '';
end;

function TQryRecArray<T>.GetCount: Integer;
begin
  Result := FQryRecInfoList.Count;
end;

function TQryRecArray<T>.Rec(Index: Integer): T;
begin
  if (Index < 0) or (Index >= FQryRecInfoList.Count) then
    raise EORMUtilsException.CreateFmt('Index %d out of bounds.', [Index]);

  Result := FQryRecInfoList[Index];
end;

procedure TQryRecArray<T>.FetchAllInstance(DBConn: TUniConnection; const QryTxt: string);
var
  qr: TUniQuery;
  RecInstance: T;
  Ctx: TRttiContext;
  ObjType: TRttiType;
  Prop: TRttiProperty;
  Field: TField;
  ORMFieldName: string;
begin
  if not Assigned(DBConn) then
    raise EORMUtilsException.Create('Database connection (DBConn) is not assigned.');

  if Trim(QryTxt).IsEmpty then
    raise EORMUtilsException.Create('Query text (QryTxt) cannot be empty.');

  qr := TUniQuery.Create(nil);
  try
    qr.Connection := DBConn;
    qr.SpecificOptions.Values['FetchAll'] := 'True';
    qr.SpecificOptions.Values['CreateConnection'] := 'False';
    qr.SQL.Text := QryTxt;
    qr.Open;

    if qr.IsEmpty then
      Exit; // No records to fetch

    Ctx := TRttiContext.Create;
    ObjType := Ctx.GetType(T);

    try
      while not qr.Eof do
      begin
        RecInstance := T.Create;
        try
          // Iterate over each property of T and assign values from the query
          for Prop in ObjType.GetProperties do
          begin
            if not Prop.IsWritable then
              Continue;

            // Attempt to find the corresponding field in the query
            Field := qr.FindField(Prop.Name);
            if not Assigned(Field) then
              Continue; // Field not found, skip

            ORMFieldName := '_' + Prop.Name;

            // Handle TNullable<T> types
            if Prop.PropertyType.TypeKind = tkRecord then
            begin
              // Expecting TNullable<T>
              // Attempt to find the backing field for the nullable property
              if ObjType.GetField(ORMFieldName) = nil then
               Continue; // Backing field not found, skip

              if Prop.PropertyType.Name.StartsWith('TNullable<') then
              begin
                // Use RTTI to determine the generic type parameter
                if Field.IsNull then
                  ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<Variant>>(NullValue))
                else
                begin
                  // Determine the generic type and set the value accordingly

                  if Prop.PropertyType.Name = 'TNullable<System.string>' then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<string>>(Field.AsString))
                  else if Prop.PropertyType.Name = 'TNullable<System.Integer>' then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<Integer>>(Field.AsInteger))
                  else if Prop.PropertyType.Name = 'TNullable<System.Int64>' then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<Int64>>(Field.AsLargeInt))
                  else if Prop.PropertyType.Name = 'TNullable<System.Extended>' then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<Extended>>(Field.AsFloat))
                  else if Prop.PropertyType.Name = 'TNullable<System.Currency>' then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<Currency>>(Field.AsCurrency))
                  else if Prop.PropertyType.Name = 'TNullable<System.TDateTime>' then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<TDateTime>>(Field.AsDateTime))
                  else if Prop.PropertyType.Name = 'TNullable<System.Boolean>' then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<Boolean>>(Field.AsBoolean))
                  else if Prop.PropertyType.Name = 'TNullable<System.Variant>' then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.From<TNullable<Variant>>(Field.Value))
                  else
                    raise EORMUtilsException.CreateFmt('Unsupported TNullable type: %s', [Prop.PropertyType.Name]);
                end;
              end
              else
                raise EORMUtilsException.CreateFmt('Unsupported record type: %s', [Prop.PropertyType.Name]);
            end
            else
            begin
              // Handle non-nullable types
              case Prop.PropertyType.TypeKind of
                tkString, tkLString, tkWString, tkUString:
                  ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), Field.AsString);
                tkInteger:
                  ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), Field.AsInteger);
                tkInt64:
                  ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), Field.AsLargeInt);
                tkFloat:
                  if Prop.PropertyType.Handle = TypeInfo(Currency) then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), Field.AsCurrency)
                  else if Prop.PropertyType.Handle = TypeInfo(TDateTime) then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), Field.AsDateTime)
                  else
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), Field.AsFloat);
                tkVariant:
                  ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), TValue.FromVariant(Field.AsVariant));
                tkEnumeration:
                  if Prop.PropertyType.Handle = TypeInfo(Boolean) then
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), Field.AsBoolean)
                  else
                    ObjType.GetField(ORMFieldName).SetValue(Pointer(RecInstance), Field.AsString);
              else
                // Unsupported type; you can extend this as needed
                Continue;
              end;
            end;
          end;

          // Add the populated record to the list
          FQryRecInfoList.Add(RecInstance);
        except
          RecInstance.Free;
          raise; // Re-raise the exception after cleanup
        end;
        qr.Next;
      end;
    finally
      // No need to free TRttiContext as it's a record
    end;
  finally
    qr.Free;
  end;
end;

function TQryRecArray<T>.GetEnumerator: TEnumerator<T>;
begin
  Result := FQryRecInfoList.GetEnumerator;
end;

class function TQryRecArray<T>.FetchAll(DBConn: TUniConnection; const QryTxt: string): TQryRecArray<T>;
var
  Instance: TQryRecArray<T>;
begin
  Instance := TQryRecArray<T>.Create;
  try
    Instance.FetchAllInstance(DBConn, QryTxt);
    Result := Instance;
  except
    Instance.Free;
    raise;
  end;
end;

end.

------------------------------------

unit interposer_class;

interface

uses
  Vcl.Forms, Vcl.Controls, CommCtrl, Messages, sPanel, sEdit, sPageControl,
  System.Classes, AdvCGrid, Uni, pixel_classes, ORM_utils, SysUtils, Dialogs,
  Generics.Collections, System.Hash, System.Rtti;

{$TYPEINFO ON}

type
  TORMKey = record
    ORMRec: TQryRecInfo;
    FieldName: string;
  end;

  TComponentHelper = class helper for TComponent
  private
    function GetORMRec: TQryRecInfo;
    function GetORMRecField: string;
  public
    property ORMRec: TQryRecInfo read GetORMRec;
    property ORMRecField: string read GetORMRecField;
  end;

  TForm = class(Vcl.Forms.TForm)
  private
    class var GORMToComponentDict: TDictionary<TORMKey, TComponent>;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function FindComponentByORMRec(ORMRec: TQryRecInfo; const FieldName: string): TComponent;
    procedure RegisterORMComponent(Component: TComponent; ORMRec: TQryRecInfo; const FieldName: string);
    procedure UnregisterORMComponent(Component: TComponent);
    procedure RegisterComponentsByHint(ORMRec: TQryRecInfo);
  end;

  TsPanel = class(sPanel.TsPanel)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

  TsEdit = class(sEdit.TsEdit)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

  TsPageControl = class(sPageControl.TsPageControl)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  private
    procedure TCMAdjustRect(var Msg: TMessage); message TCM_ADJUSTRECT;
  end;

  TAdvColumnGrid = class(AdvCGrid.TAdvColumnGrid)
  private
    FByPassAF: TArray<Boolean>;
    function GetCellz(ACol, ARow: Integer): TZString;
    procedure SetCellz(ACol, ARow: Integer; const Value: TZString);
    function GetBypassAF(ACol: Integer): Boolean;
    procedure SetBypassAF(ACol: Integer; const Value: Boolean);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    property Cellz[ACol, ARow: Integer]: TZString read GetCellz write SetCellz;
    property BypassAutoFit[ACol: Integer]: Boolean read GetBypassAF write SetBypassAF;
  published
    function CriaLinhaObjeto(MyObject: TObject): Integer;
    function CriaLinha: Integer;
    function GetColumnIndexByName(const nome: string): Integer;
    procedure SetBasicColumnConfig;
  end;

implementation

uses
  pixel_utils, System.Math, System.Types, Windows, TypInfo, System.Generics.Defaults,
  Data.DB, Vcl.Graphics, ComCtrls, Vcl.Grids;

// Helper function for RTTI component registration
procedure TForm.RegisterComponentsByHint(ORMRec: TQryRecInfo);
var
  Context: TRttiContext;
  RttiType: TRttiType;
  RttiProperty: TRttiProperty;
  Component: TComponent;
  HintValue: TValue;
begin
  Context := TRttiContext.Create;
  try
    for Component in Self do
    begin
      RttiType := Context.GetType(Component.ClassType);
      RttiProperty := RttiType.GetProperty('Hint');

      if Assigned(RttiProperty) then
      begin
        HintValue := RttiProperty.GetValue(Component);
        if HintValue.IsEmpty then
          Continue;

        // Use property names of the ORMRec object
        RttiType := Context.GetType(ORMRec.ClassType);
        for RttiProperty in RttiType.GetProperties do
        begin
          if (RttiProperty.Visibility = mvPublished) then
          begin
            // Register component if its Hint matches a property name in ORMRec
            if SameText(HintValue.AsString, RttiProperty.Name) then
            begin
              RegisterORMComponent(Component, ORMRec, RttiProperty.Name);
              Break; // Once registered, no need to check other properties for the same component
            end;
          end;
        end;
      end;
    end;
  finally
    Context.Free;
  end;
end;

// Existing function definitions...

function TORMKeyHash(const Key: TORMKey): Integer;
begin
  Result := Integer(NativeUInt(Key.ORMRec)) xor THashBobJenkins.GetHashValue(LowerCase(Key.FieldName));
end;

function TORMKeyEquals(const Key1, Key2: TORMKey): Boolean;
begin
  Result := (Key1.ORMRec = Key2.ORMRec) and SameText(Key1.FieldName, Key2.FieldName);
end;

var
  GORMRecDictionary: TDictionary<TComponent, TQryRecInfo>;
  GORMRecFieldDictionary: TDictionary<TComponent, string>;

// Methods for TComponentHelper

function TComponentHelper.GetORMRec: TQryRecInfo;
begin
  if not GORMRecDictionary.TryGetValue(Self, Result) then
    Result := nil;
end;

function TComponentHelper.GetORMRecField: string;
begin
  if not GORMRecFieldDictionary.TryGetValue(Self, Result) then
    Result := '';
end;

// Methods for TForm

constructor TForm.Create(AOwner: TComponent);
begin
  inherited;
end;

destructor TForm.Destroy;
begin
  inherited;
end;

procedure TForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  StrPCopy(Params.WinClassName, 'ZPro');
end;

procedure TForm.RegisterORMComponent(Component: TComponent; ORMRec: TQryRecInfo; const FieldName: string);
var
  Key: TORMKey;
begin
  Key.ORMRec := ORMRec;
  Key.FieldName := FieldName;

  if (Key.ORMRec <> nil) and (Key.FieldName <> '') then
  begin
    GORMRecDictionary.AddOrSetValue(Component, ORMRec);
    GORMRecFieldDictionary.AddOrSetValue(Component, LowerCase(FieldName)); // Store lowercase for consistent hashing
    GORMToComponentDict.AddOrSetValue(Key, Component);
  end;
end;

procedure TForm.UnregisterORMComponent(Component: TComponent);
var
  ORMRec: TQryRecInfo;
  FieldName: string;
  Key: TORMKey;
begin
  if GORMRecDictionary.TryGetValue(Component, ORMRec) and GORMRecFieldDictionary.TryGetValue(Component, FieldName) then
  begin
    Key.ORMRec := ORMRec;
    Key.FieldName := LowerCase(FieldName);
    GORMToComponentDict.Remove(Key);
    GORMRecDictionary.Remove(Component);
    GORMRecFieldDictionary.Remove(Component);
  end;
end;

function TForm.FindComponentByORMRec(ORMRec: TQryRecInfo; const FieldName: string): TComponent;
var
  Key: TORMKey;
begin
  Key.ORMRec := ORMRec;
  Key.FieldName := LowerCase(FieldName); // Use lowercase for lookup

  if not GORMToComponentDict.TryGetValue(Key, Result) then
    Result := nil;
end;

// Other class methods remain unchanged...

procedure TsPanel.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  StrPCopy(Params.WinClassName, 'Painel');
end;

procedure TsEdit.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  StrPCopy(Params.WinClassName, 'Editor');
end;

procedure TsPageControl.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  StrPCopy(Params.WinClassName, 'PagCtrl');
end;

procedure TsPageControl.TCMAdjustRect(var Msg: TMessage);
begin
  inherited;
  case TabPosition of
    tpTop:
      begin
        PRect(Msg.LParam)^.Left := 0;
        PRect(Msg.LParam)^.Right := ClientWidth;
        PRect(Msg.LParam)^.Bottom := ClientHeight;
      end;
  end;
end;

procedure TAdvColumnGrid.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  StrPCopy(Params.WinClassName, 'Grid');
end;

function TAdvColumnGrid.GetCellz(ACol, ARow: Integer): TZString;
begin
  Result := Self.Cells[ACol, ARow];
end;

procedure TAdvColumnGrid.SetCellz(ACol, ARow: Integer; const Value: TZString);
begin
  Self.Cells[ACol, ARow] := string(Value);
end;

function TAdvColumnGrid.GetBypassAF(ACol: Integer): Boolean;
begin
  Result := FByPassAF[ACol];
end;

procedure TAdvColumnGrid.SetBypassAF(ACol: Integer; const Value: Boolean);
begin
  if Length(FByPassAF) < ACol + 1 then
    SetLength(FByPassAF, ACol + 1);
  FByPassAF[ACol] := Value;
end;

function TAdvColumnGrid.CriaLinha: Integer;
begin
  Self.RowCount := Self.RowCount + 1;
  Self.ClearRows(Self.RowCount - 1, 1);
  Result := Self.RowCount - 1;
end;

function TAdvColumnGrid.CriaLinhaObjeto(MyObject: TObject): Integer;
begin
  Self.RowCount := Self.RowCount + 1;
  Self.ClearRows(Self.RowCount - 1, 1);
  Self.Objects[0, Self.RowCount - 1] := MyObject;
  Result := Self.RowCount - 1;
end;

function TAdvColumnGrid.GetColumnIndexByName(const nome: string): Integer;
begin
  Result := 0;
  for var i := 1 to Pred(Self.ColCount) do
    if Self.Columns[i].Name = nome then
      Exit(i);
end;

procedure TAdvColumnGrid.SetBasicColumnConfig;
var
  i: Integer;
begin
  with Self do
  begin
    SuppressColumn(0);
    for i := 1 to ColCount - 1 do
      if Columns[i].Tag = 0 then
      begin
        Columns[i].HeaderAlignment := taCenter;
        Columns[i].HeaderFont.Name := 'Tahoma';
        Columns[i].HeaderFont.Size := MulDiv(8, 96, Self.CurrentPPI);
        Columns[i].HeaderFont.Color := clWhite;
        Columns[i].HeaderFont.Style := [fsBold];
      end;
    for i := 1 to ColCount - 1 do
      if Columns[i].Tag = 0 then
      begin
        Columns[i].Font.Name := 'Verdana';
        Columns[i].Font.Size := MulDiv(10, 96, Self.CurrentPPI);
        Columns[i].Font.Style := [];
      end;
    for i := 1 to ColCount - 1 do
      if Columns[i].Tag = 0 then
      begin
        Columns[i].ShowBands := True;
        Colors[i, 0] := RGB($41, $3F, $42);
      end;

    for i := 1 to ColCount - 1 do
      Columns[i].Tag := 1;

    Bands.PrimaryColor := $00EFEFEF;
    Bands.SecondaryColor := $00F9F9F9;
    MouseActions.DirectEdit := True;
    MouseActions.DirectComboDrop := True;
    Bands.Active := True;
    ActiveCellShow := False;
    Navigation.SkipDisabledRows := True;
    Navigation.AutoComboSelect := False;
    ShowSelection := True;
    HideFocusRect := True;
    Options := Options - [goRangeSelect] + [goRowSelect];
    HoverRow := True;
    HoverRowColor := clYellow;
    ActiveRowShow := True;
    ActiveRowColor := clLime;
    SelectionColor := clLime;
    SelectionTextColor := clBlack;
    ColumnSize.Stretch := False;
    ColumnSize.StretchColumn := -1;
    ColumnSize.SynchWithGrid := False;
    FixedRowAlways := True;
    FixedRows := 1;
  end;
end;

initialization
  GORMRecDictionary := TDictionary<TComponent, TQryRecInfo>.Create;
  GORMRecFieldDictionary := TDictionary<TComponent, string>.Create;

  // Initialize dictionary with custom equality and hash functions
  TForm.GORMToComponentDict := TDictionary<TORMKey, TComponent>.Create(
    TEqualityComparer<TORMKey>.Construct(TORMKeyEquals, TORMKeyHash)
  );

finalization
  GORMRecDictionary.Free;
  GORMRecFieldDictionary.Free;
  TForm.GORMToComponentDict.Free;

end.