System Type Converters

LLBLGen Pro knows two kinds of type converters: the normal type converters (as they were defined prior to v3.5) and system type converters. The normal type converters are used by users to add whatever type converter they please while system type converters can be used to obtain information about built-in conversions in the target framework used.

As a system type converter is only used by the designer, it doesn't do any conversion, it only implements the CanConvertTo/From/CreateInstance methods, as the templates will use the information from the framework file to emit code to use a conversion known in the target framework, not the conversion code in the type converter itself.

This means that system type converters have their conversion part implemented in the target framework used. If the target framework doesn't offer this kind of conversion logic, a system type converter can't be used for the particular target framework. Currently the LLBLGen Pro Runtime Framework and Entity Framework Core 2.1+ support system type converter logic.

Entity Framework, Entity Framework Core 2.0 and earlier, and Linq to SQL don't support any kind of type converter system. NHibernate supports normal type converters, as long as they implement IUserType. See the NHibernate Support manual shipped with LLBLGen Pro for further details on these type converters for NHibernate as well as an example.

System type converters are annotated with the attribute System.ComponentModel.DesignOnlyAttribute. Every type converter with that attribute is considered a type converter which doesn't have runtime conversion code on board and can only be used as a system type converter.

The shipped system type converters cover most typical conversions. This makes using type converters easier, as users don't have to write their own type converters to do common conversions. It also makes it easier to define type conversion definitions as the type converter is already there.

To easily assign type converters, it's recommended you use type conversion definitions.

Implicit numeric conversions

The designer can deal with implicit numeric conversions. Implicit numeric conversions are conversions between e.g. byte and int, float and long etc., using Convert.ChangeType(value, targetType). If the target framework states it supports implicit numeric conversions, the designer will assume any type mismatch between two numeric types can be resolved by the target framework.

The following numeric types are supported: byte, sbyte, short, int, long, ushort, uint, ulong, float, double, decimal. An implicit numeric conversion is required if the model type and the meta-data type on a field mapping have one of these types but are not equal (e.g. entity field type is int and table field type is byte)

Implicit numeric conversions are supported by Entity Framework Core 2.1+ and the LLBLGen Pro Runtime Framework.

Implicit enum conversions

Besides dealing with implicit numeric conversions, the designer can also deal with implicit enum conversions. Implicit enum conversions are conversions between an Enum type and either a normal numeric type like int, or a string. If the target framework states it supports implicit enum conversions, the designer will assume any type mismatch between an enum type on the model side an a normal numeric type or a string can be resolved by the target framework.

All supported target frameworks support implicit conversions between Enum and a normal numeric type like int and byte. Implicit conversions between Enum and string (where the string represents the value of the enum in string format), are supported by Entity Framework Core 2.1+ and the LLBLGen Pro Runtime Framework.

Changing target framework: removal of invalid system type converters

If the user switches target frameworks, it can be there are type converters specified on mappings which are no longer valid, because they're system type converters and the chosen target framework doesn't support them as such.

When this happens, the system type converters defined on mappings which are no longer valid, as the newly chosen target framework doesn't define them as system type converters, are removed from the mappings. Type conversion definitions as well have to be updated, as some type converters might not be available anymore.

System type converters shipped with the designer

The following system type converters are shipped with the designer and are supported by one or more frameworks. They're all marked with the DesignOnly attribute and therefore require that at runtime other code performs the actual conversion of the values as they don't contain any conversion code themselves. Per type converter, the framework which supports the actual conversion at runtime by default, has been specified. If a framework isn't specified, it requires a normal type converter to be used (like with NHibernate) or it doesn't support type converters at all (Entity Framework, Entity Framework Core 2.0 and earlier, Linq to SQL).

Info

Target frameworks which support implicit numeric conversions, like Entity Framework Core 2.1+ and LLBLGen Pro Runtime Framework, don't require a type converter for these conversions, and therefore even if a framework is listed with a type converter below which converts numeric values (e.g. Int64 to Decimal), it isn't required to use the type converter to use this conversion at runtime for the frameworks which support implicit numeric conversions. The type converters are still included for backwards compatibility.

  • Bool <-> Numeric.
    Type: BooleanNumericConverter.
    Db field .NET types supported: byte/int16/int32/int64/decimal/sbyte/uint16/uint32/uint64
    Frameworks supporting this conversion: Entity Framework Core 2.1+, LLBLGen Pro Runtime Framework
  • Bool <-> Char (Y/N)
    Type: *BooleanCharYNConverter
    Db field .NET types supported: string, char. First character is used for conversion. Result is always a string/char of 1 length.
    Frameworks supporting this conversion: Entity Framework Core 2.1+, LLBLGen Pro Runtime Framework
  • Byte <-> Decimal
    Type: ByteDecimalConverter
    Db field .NET types supported: Decimal
    Frameworks supporting this conversion: LLBLGen Pro Runtime Framework
  • Byte[] <-> string.
    Type: ByteArrayStringConverter.
    Db field .NET types supported: string
    Frameworks supporting this conversion: Entity Framework Core 2.1+, LLBLGen Pro Runtime Framework
  • Char <-> String(1)
    Type: CharStringConverter.
    Db field .NET types supported: String
    Frameworks supporting this conversion: Entity Framework Core 2.1+, LLBLGen Pro Runtime Framework
  • DateTimeOffset <-> Binary
    Type: DateTimeOffsetBinaryConverter.
    Db field .NET types supported: Int64
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • DateTimeOffset <-> byte[]
    Type: DateTimeOffsetByteArrayConverter.
    Db field .NET types supported: byte[]
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • DateTimeOffset <-> string
    Type: DateTimeOffsetStringConverter.
    Db field .NET types supported: string
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • DateTime <-> Binary
    Type: DateTimeBinaryConverter.
    Db field .NET types supported: Int64
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • DateTime <-> Int64
    Type: DateTimeInt64Converter.
    Db field .NET types supported: Int64
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • DateTime <-> string
    Type: DateTimeStringConverter.
    Db field .NET types supported: string
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • DateTime (local timezone is used) <-> DateTimeUTC
    Type: DateTimeDateTimeUTCConverter
    Db field .NET types supported: DateTime
    Frameworks supporting this conversion: LLBLGen Pro Runtime Framework
  • DateTime <-> string
    Type: DateTimeStringConverter.
    Db field .NET types supported: string
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • Double <-> Decimal
    Type: DoubleDecimalConverter
    Db field .NET types supported: Decimal
    Frameworks supporting this conversion: LLBLGen Pro Runtime Framework
  • Int16 <-> Decimal
    Type: Int16DecimalConverter
    Db field .NET types supported: Decimal
    Frameworks supporting this conversion: LLBLGen Pro Runtime Framework
  • Int32 <-> Decimal
    Type: Int32DecimalConverter
    Db field .NET types supported: Decimal
    Frameworks supporting this conversion: LLBLGen Pro Runtime Framework
  • Int64 <-> Decimal
    Type: Int64DecimalConverter
    Db field .NET types supported: Decimal
    Frameworks supporting this conversion: LLBLGen Pro Runtime Framework
  • Guid <-> String (char(32))
    Type: GuidStringConverter
    Db field .NET types supported: string
    Frameworks supporting this conversion: Entity Framework Core 2.1+, LLBLGen Pro Runtime Framework
  • Guid <-> byte[]
    Type: GuidByteArrayConverter
    Db field .NET types supported: byte[]
    Frameworks supporting this conversion: Entity Framework Core 2.1+, LLBLGen Pro Runtime Framework
  • Single <-> Decimal
    Type: SingleDecimalConverter
    Db field .NET types supported: Decimal
    Frameworks supporting this conversion: LLBLGen Pro Runtime Framework
  • String <-> byte[]
    Type: StringByteArrayConverter
    Db field .NET types supported: byte[]
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • TimeSpan <-> Int64
    Type: TimeSpanInt64Converter.
    Db field .NET types supported: Int64
    Frameworks supporting this conversion: Entity Framework Core 2.1+
  • TimeSpan <-> string
    Type: TimeSpanStringConverter.
    Db field .NET types supported: string
    Frameworks supporting this conversion: Entity Framework Core 2.1+

Defining a custom TypeConverter for Entity Framework Core

The designer supports type converter types derived from System.ComponentModel.TypeConverter, however type converters used at runtime by Entity Framework Core derive from Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter.

To be able to use a ValueConverter derived type converter in the LLBLGen Pro designer, you have to define a system type converter with the same name and namespace. This system type converter is then used with mappings and the variant with the same name and namespace is then used with the generated code at runtime.

Info

For the LLBLGen Pro Runtime Framework, you don't need to do this, you can use the type converter you'll use at runtime also in the designer. This section is for Entity Framework Core users only.

Example: ByteToIntConverter

To illustrate this, below are the two classes, one is for the designer, the other is for usage at runtime.

System type converter part

The system type converter part is the class below. It has to be in its own assembly and compiled against .NET Framework v4.5.2 or higher. Of course you have to change the namespace if you want to use it yourself.

using System;
using System.ComponentModel;

namespace MyNamespace.TypeConverters
{
    /// <summary>
    /// Definition of the ByteToIntConverter. This converter uses 'Byte' as its core type and converts any int value to and from byte
    /// </summary>
    [Description("Converter with as core type System.Byte, for mapping a field with a .NET type System.Byte onto a int database field")]
    public class ByteToIntConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(int);
        }


        /// <inheritdoc />
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(byte);
        }


        /// <summary>
        /// Creates an instance of the Type that this <see cref="T:System.ComponentModel.TypeConverter"/> is associated with (short)
        /// </summary>
        /// <param name="context">ignored.</param>
        /// <param name="propertyValues">ignored.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> of type short. It always returns 0 for this converter.
        /// </returns>
        public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
        {
            return (byte)0;
        }
        
        // rest of the methods not needed for the designer.
    }
}

After you've compiled this assembly, place the DLL either in the <LLBLGen Pro installation folder>\TypeConverters folder, or in the folder specified in the project settings -> Entity Model -> General -> Additional type converter folder. The designer will then pick up this type converter the next time you start the designer or load the project, and you can use it in mappings.

The generated code will have references to the type MyNamespace.TypeConverters.ByteToIntConverter. However that type isn't the type above, as that type isn't usable by Entity Framework Core. Instead you use the runtime part below.

Runtime type converter part

To use the ByteToIntConverter defined in the mappings at runtime, you need a ValueConverter derived type. This is the type below.

using System;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace MyNamespace.TypeConverters
{
    public class ByteToIntConverter : ValueConverter<byte, int>
    {
        public ByteToIntConverter(ConverterMappingHints hints=null) 
            : base( v=> Convert.ToInt32(v), v=>Convert.ToByte(v), hints)
        {
        }
    }
}

This type too has to be in its own assembly, and as it's using the same name as our System type converter part, you need to place this in its own project. After you've compiled this assembly, reference this DLL in your generated code project containing the mappings (the cs/vbproj with the context and modelbuilder classes).

The key is to use the same namespace and type name for the system type converter part (which has to derive from TypeConverter and is used to satisfy the designer so you can use the type converter in mappings) and the runtime part which is used by Entity Framework Core (and has to derive from ValueConverter)