TValueConverterFactory does not return a converter for a Nullable<EnumType>

Issue #207 resolved
Todd Flora created an issue

We have the following type defined:

  TDocumentItemType = (
    ditNone,    //none
    ditSale,    //Sale
    ditReturn,  //Return
    ditOrder,   //Order
    ditExchange, //Exchange
    ditVoid      //Item was voided
  );

And then a Field in one of our ORM Model files as follows:

    [Column('ITEM_TYPE',[],1,0)]
    FItemType: Nullable<TDocumentItemType>;

When the ORM attempts to read the data and convert it the following error occurs:

Capture.JPG

It would seem that it is valid to have a Nullable Enumerated type as the database can certaintily have no value.

After tracing into the code it seems that the TValueConverterFactory does not return a Converter for a Nullable<TEnumType> type.

Is it possible to add a converter for nullable enum types.

Fails here with no converter.

function TDefaultConverter.TryConvertToParam(const value: TValue;
  const targetTypeInfo: PTypeInfo;
  out targetValue: TValue;
  const parameter: TValue): Boolean;
var
  converter: IValueConverter;
begin
  converter := TValueConverterFactory.GetConverter(value.TypeInfo, targetTypeInfo);
  Result := Assigned(converter)
    and converter.TryConvertTo(value, targetTypeInfo, targetValue, parameter);
  if not Result then
{$IFNDEF DELPHIXE2_UP}
    // workaround for wrong TValue.TryCast for string to float (it calls ConvStr2Str by mistake)
    if not ((value.Kind in [tkString, tkLString, tkWString, tkUString])
      and (targetTypeInfo.Kind = tkFloat)) then
{$ENDIF}
    Result := value.TryCast(targetTypeInfo, targetValue);
end;

Comments (10)

  1. Todd Flora reporter

    So I write a test for this to hopefully help you see the issue. Into the Spring.Tests.ValueConverters unit TTestFromInteger fixture.

    procedure TTestFromInteger.TestIntegerToNullableEnum;
    var
      outValue: TValue;
      outNullable: Nullable<TEnumeration>;
    begin
      outValue := fConverter.ConvertTo(TValue.From<Integer>(1),
        TypeInfo(Nullable<TEnumeration>));
      CheckFalse(outValue.IsEmpty);
      CheckTrue(outValue.TryAsType<Nullable<TEnumeration>>(outNullable));
      CheckEquals(1, Integer(outNullable.Value));
    end;
    
  2. Stefan Glienke repo owner

    If there is no converter registered, it cannot return one, simple. Write a converter for Integer<->TDocumentItemType and register it.

  3. Todd Flora reporter

    We use enum types a lot. It would be better to have one converter that knew how to convert any enum. Can you suggest how to do this?

  4. Stefan Glienke repo owner

    Look into Spring.ValueConverters.pas - there are multiple converters for nullable to inner type and vice versa and integer<->enum. You just need one for integer <-> nullable<enum>. The trick however will be the correct registration if you want to make it for all nullable enums in general and not for each enum type explicitly. But I guess you'll figure it out.

  5. Log in to comment