Managing field data types

All data types assignable via the field editor or used by form components must be explicitly registered. The system uses the metadata provided during registration to:

  • generate the database columns storing the values of individual fields,
  • configure code generator and field editor behavior,
  • perform value conversions (and object mapping for complex types) when fetching data to and from the database.

The following table highlights important types registered by default:

Field editor name

C# data type

Database representation

Notes

Boolean (Yes/No)

bool

bit

Binary

byte[]

varbinary(max)

Integer number

int

int

Long integer number

long

bigint

Floating-point number (Double precision)

double

float

Decimal number

decimal

decimal

Date

DateTime

date

Date and time

DateTime

datetime2

Time interval

TimeSpan

time

Text

string

nvarchar

Database field length configurable when creating or editing fields (up to the database maximum). 

Long text

string

nvarchar(max)

Unique identifier (GUID)

Guid

uniqueidentifier

Register custom data types

The default set of data types can be extended using the DataTypeManger class, which allows you to register additional data types into the system via the RegisterDataTypes(params DataType[]) method. Data type registrations must be done during application startup.

The DataType<T> class provides multiple constructors suitable depending on the complexity of the type being registered.

For primitive types and simple objects that can be directly serialized to the database, use




DataType<T>(string sqlType, string fieldType, string schemaType, Func<object, T, CultureInfo, T> conversionFunc)


where:

  • T – generic substituted with the C# type of the data type being registered.
  • sqlType – the SQL type of the database column storing the values of the DataType.
  • fieldType – the string identifier of the data type in the system.
  • schemaType – the XSD data type (xs:string, xs:integer, etc.) used for XML serialization into IDataContainer.
  • conversionFunc – the function used to convert the stored database value to the data type. Must be static.

For composite types, use 




DataType<T>(string sqlType, string fieldType, string schemaType, Func<object, T, CultureInfo, T> conversionFunc, Func<T, object, CultureInfo, object> dbConversionFunc, IDataTypeTextSerializer textSerializer)


where:

  • T – generic substituted with the C# type of the data type being registered.
  • sqlType – the SQL type of the database column storing the values of the DataType.
  • fieldType – the string identifier of the data type in the system.
  • schemaType – the XSD data type (xs:string, xs:integer, etc.) used for XML serialization into IDataContainer. For composite types, this is commonly set to xs:string, as you’re often storing a serialized object (e.g., as a JSON string).
  • dbConversionFunc – the function used to convert the data type to its string representation for storage in the database (e.g., a JSON string, XML, custom format). Must be static.
  • conversionFunc – the function used to convert the stored database value to the data type. Must be static.

For example, the composite type MyCompositeType:




public class MyCompositeType
{
    public int Identifier { get; set; }
    public string Name { get; set; }
}


would use the following registration:




// Called on application startup
DataTypeManager.RegisterDataTypes(
    new DataType<MyCompositeType>("nvarchar(max)", "mydatatype", "xs:string",
                                    MyCompositeTypeHelper.ConvertToSystemRepresentation, 
                                    MyCompositeTypeHelper.ConvertToDbRepresentation, 
                                    new DefaultDataTypeTextSerializer("mydatatype"))
                {
                    // Data type configuration, see the 'Data type configuration' section for details
                }
);

public static class MyCompositeTypeHelper
{   
    public static object ConvertToDbRepresentation(MyCompositeType value, object defaultValue, CultureInfo culture)
    {
        if (value == null)
        {
            return defaultValue;
        }

        try
        {
            return JsonSerializer.Serialize(value);
        }
        catch (Exception e)
        {
            throw new InvalidOperationException("An error occurred when serializing the data type, see the inner exception for details", e);
        }
    } 

    public static MyCompositeType ConvertToSystemRepresentation(object value, MyCompositeType defaultValue, CultureInfo culture)
    {
        if (value == null)
        {
            return defaultValue;
        }

        // We know the value is stored in the database as a JSON string
        var stringValue = value as string;
        if (string.IsNullOrEmpty(stringValue))
        {
            return defaultValue;
        }

        try
        {
            return JsonSerializer.Deserialize<MyCompositeType>(stringValue);
        }
        catch (Exception e)
        {
            throw new InvalidOperationException("An error occurred when deserializing the data type, see the inner exception for details", e);
        }
    }
}


The data type is now registered and can be assigned to object fields via the field editor. Note that to edit fields based on this data type, you also need to develop corresponding form components.

Data type configuration

During data type registration, you can also configure the following properties that control the behavior of the system when working with the data type in code generators, the field editor, and database queries. 

Field editor

  • Hidden – indicates whether the data type is hidden from the field editor interface.
  • HasConfigurableDefaultValue – indicates whether the data type needs a configurable default value. Controls the visibility of the default value editor in the field editor interface.

Code generators

  • TypeAlias – C# type assigned to properties generated from fields based on the data type.
  • DefaultValueCode – C# code for the default value of the data type. Provided as a string literal. For example: String.Empty

General

  • DbTypeSystem.Data.SqlDbType used when generating database queries. Set to the same type as the data type’s sqlType parameter.
  • VariableSize – indicates that the type can have variable size. For example, nvarchar(value). If set to true, the field editor interface also offers a Size field that allows users to set the size of the underlying database column.
    • DefaultSize – used when size isn’t provided via the field editor.
  • VariablePrecision – indicates that the type can have variable precision (e.g., floats). If set to true, the field editor interface also offers a Precision field that allows users to set the precision of the underlying database column.
    • DefaultPrecision – used when precision isn’t provided via the field editor.