Invalid variant type conversion

Issue #119 resolved
Albert kobina Arhin created an issue

Hi Linas, I am having issues mapping a MS SQL VarBinary Field to a String in a test App. Below is my PODO.

type
  [Entity]
  [Table('META_USERS')]
   TUser = class
     private
        [Column('USERID', [cpRequired, cpPrimaryKey, cpNotNull, cpDontInsert])]
        [AutoGenerated]
        FUserID : Int32;
        [Column('LOGIN_NAME', [])]
        FLoginName : string;
        [Column('FULL_NAME', [])]
        FFullName : string;
        [Column('PASSWORD', [])]
        FPassword : string;
     public
         property UserID : Int32 read FUserID write FUserID;
         property LoginName : string read FLoginName write FLoginName;
         property FullName : string read FFullName write FFullname ;
         property Password : string read FPassword write FPassword;
   end;

A DAO

 TUserDBO = class
    FDBSession : TSession;
    public
      constructor Create;
      destructor destroy;overload;
      function GetAllUsers : IList<TUser>;
  end;

implementation

uses
  MetaADOConnectionUtils;

constructor TUserDBO.Create;
begin
  FDBSession := TDBConnection.GetInstance.CreateDBSessionManager;
end;

destructor TUserDBO.destroy;
begin
   FDBSession.Connection.Disconnect;
   FDBSession.Free;
   FDBSession := nil;
   inherited;
end;

function TUserDBO.GetAllUsers : IList<TUser>;
begin
   Result := FDBSession.FindAll<TUser>;
end;

and the call code on a form

var
  AllUsers : IList<TUser>;
  dao : TUserDBO;
  aUser : TUser;
begin
   dao := TUserDBO.Create;
   AllUsers := dao.GetAllUsers;
   Memo5.Lines.Clear;
      for aUser in AllUsers do
       Memo5.Lines.Add(aUser.LoginName)

The above codes raises above error but works all right if the Password Mapping which is a varbinary is commented out.

Comments (6)

  1. Stefan Glienke repo owner

    Where does the exception come from? From Spring.TValueHelper.FromVariant? If so then the varbinary to string conversion needs to be added. I just don't know what the vartype of a varbinary field is from the top of my head.

  2. Stefan Glienke repo owner

    The ORM does not convert varbinary (which is internally treated as TArray<Byte>) to string by itself.

    However using the TValueConverters you can register a converter that handles this. I recommend not using TArray<Byte> to string conversion but use a new string type for your password field to it only handles this explicit type.

    type
      VarBinaryPasswordString = type string;
    
      [Table('TEST')]
      TTest = class
        [Column([cpPrimaryKey])]
        Id: Integer;
        [Column]
        Password: VarBinaryPasswordString;
      end;
    

    Then define the converter and register it:

    uses
      Spring.ValueConverters;
    
    type
      TByteArrayToStringConverter = class(TValueConverter)
      protected
        function DoConvertTo(const value: TValue;
          const targetTypeInfo: PTypeInfo;
          const parameter: TValue): TValue; override;
      end;
    
    function TByteArrayToStringConverter.DoConvertTo(const value: TValue;
      const targetTypeInfo: PTypeInfo; const parameter: TValue): TValue;
    begin
      Result := TEncoding.Unicode.GetString(value.AsType<TArray<Byte>>); 
      // or another encoding depending on how the string is saved in the database
    end;
    
      TValueConverterFactory.RegisterConverter(TypeInfo(TArray<Byte>),
        TypeInfo(VarBinaryPasswordString), TByteArrayToStringConverter);
    

    You also need the other way around if you want to save the value. This is currently broken and I am fixing this.

  3. Log in to comment