Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 610
OrmLite Type Converters
OrmLite has become a lot more customizable and extensible thanks to the internal redesign decoupling all custom logic for handling different Field Types into individual Type Converters.
This use of individual decoupled Type Converters makes it possible to enhance or entirely replace how .NET Types are handled and can also be extended to support new Types it has no knowledge about, a feature taken advantage of by the SQL Server Types support.

Converters allows for great re-use as common functionality to support each type is maintained in the common ServiceStack.OrmLite/Converters whilst any RDBMS-specific functionality can inherit the common converters and provide any specialization required to support that type. E.g. SQL Server specific converters are maintained in ServiceStack.OrmLite.SqlServer/Converters with each converter inheriting shared functionality and only adding custom logic required to support that Type in Sql Server.
Converters also provide good encapsulation as everything relating to handling the field type is contained within
a single class definition. A Converter is any class implementing
IOrmLiteConverter
although it's instead recommended to inherit from the OrmLiteConverter abstract class which allows
only the minimum API's needing to be overridden, namely the ColumnDefinition
used when creating the Table definition and the ADO.NET DbType it should use in parameterized queries.
An example of this is in
GuidConverter:
publicclassGuidConverter:OrmLiteConverter{publicoverridestringColumnDefinition{get{return"GUID";}}publicoverrideDbTypeDbType{get{returnDbType.Guid;}}}For this to work in SQL Server the ColumnDefinition should instead be UniqueIdentifier which is also
what it needs to be cast to, to be able to query Guid's within an SQL Statement.
Therefore Guids require a custom
SqlServerGuidConverter
to support Guids in SQL Server which looks like:
publicclassSqlServerGuidConverter:GuidConverter{publicoverridestringColumnDefinition{get{return"UniqueIdentifier";}}publicoverridestringToQuotedString(TypefieldType,objectvalue){varguidValue=(Guid)value;returnstring.Format("CAST('{0}' AS UNIQUEIDENTIFIER)",guidValue);}}To get OrmLite to use this new Custom Converter for SQL Server, the SqlServerOrmLiteDialectProvider just
registers it in its constructor:
base.RegisterConverter<Guid>(newSqlServerGuidConverter());i.e. overriding the pre-registered GuidConverter to enable its extended functionality in SQL Server.
You'll also use the same RegisterConverter<T>() API to register your own Custom Guid Coverter on the RDBMS
provider you want it to apply to, e.g for SQL Server:
SqlServerDialect.Provider.RegisterConverter<Guid>(newMyCustomGuidConverter());If needed, it can be later retrieved with:
IOrmLiteConverterconverter=SqlServerDialect.Provider.GetConverter<Guid>();varmyGuidConverter=(MyCustomGuidConverter)converter;Custom Converters also makes it easier to debug Type issues where if you want to see what value gets retrieved from the database, you can override and add a breakpoint on the base method letting you inspect the value returned from the ADO.NET Data Reader:
publicclassMyCustomGuidConverter:SqlServerGuidConverter{publicoverrideobjectFromDbValue(TypefieldType,objectvalue){returnbase.FromDbValue(fieldType,value);//add breakpoint}}An example of when you'd want to do this is if you wanted to use the Guid property in your POCO's on
legacy tables which stored Guids in VARCHAR columns, in which case you can also add support for converting
the returned strings back into Guid's with:
publicclassMyCustomGuidConverter:SqlServerGuidConverter{publicoverrideobjectFromDbValue(TypefieldType,objectvalue){varstrValue=valueasstring;returnstrValue!=null?newGuid(strValue);:base.FromDbValue(fieldType,value);}}Another popular Use Case now enabled with Converters is being able to override built-in functionality based on preference. E.g. by default TimeSpans are stored in the database as Ticks in a BIGINT column since it's the most reliable way to retain the same TimeSpan value uniformly across all RDBMS's.
E.g SQL Server's TIME data type can't store Times greater than 24 hours or with less precision than 3ms. But if using a TIME column was preferred it can now be enabled by registering to use the new SqlServerTimeConverter instead:
SqlServerDialect.Provider.RegisterConverter<TimeSpan>(newSqlServerTimeConverter{Precision=7});Another benefit is they allow for easy customization as seen with Precision property which will now
create tables using the TIME(7) Column definition for TimeSpan properties.
For RDBMS's that don't have a native Guid type like Oracle or Firebird, you had an option to choose whether
you wanted to save them as text for better readability (default) or in a more efficient compact binary format.
Previously this preference was maintained in a boolean flag along with multiple Guid implementations hard-coded
at different entry points within each DialectProvider. This complexity has now been removed, now to store guids
in a compact binary format you'll instead register the preferred Converter implementation, e.g:
FirebirdDialect.Provider.RegisterConverter<Guid>(newFirebirdCompactGuidConverter());To customize the behavior of how strings are stored you can change them directly on the StringConverter, e.g:
StringConverterconverter=OrmLiteConfig.DialectProvider.GetStringConverter();converter.UseUnicode=true;converter.StringLength=100;Which will change the default column definitions for strings to use NVARCHAR(100) for RDBMS's that support
Unicode or VARCHAR(100) for those that don't.
The GetStringConverter() API is just an extension method wrapping the generic GetConverter() API to return
a concrete type:
publicstaticStringConverterGetStringConverter(thisIOrmLiteDialectProviderd){return(StringConverter)d.GetConverter(typeof(string));}It's now much simpler and requires less effort to implement new features that maintain the same behavior
across all supported RDBM's thanks to better cohesion, re-use and reduced internal state. One new feature
we've added as a result is the new DateStyle customization on DateTimeConverter which lets you change how
Date's are persisted and populated, e.g:
DateTimeConverterdates=OrmLiteConfig.DialectProvider.GetDateTimeConverter();dates.DateStyle=DateTimeKind.Local;Will save DateTime in the database and populate them back on data models as LocalTime.
This is also available for Utc:
dates.DateStyle=DateTimeKind.Utc;Default is Unspecified which doesn't do any conversions and just uses the DateTime returned by the ADO.NET provider.
Examples of the behavior of the different DateStyle's is available in
DateTimeTests.
SQL Server Converter for NodaTimeInstant Type in DATETIMEOFFSET with TimeZone:
publicclassSqlServerInstantConverter:OrmLiteConverter{publicoverridestringColumnDefinition=>"DATETIMEOFFSET";publicoverrideDbTypeDbType=>DbType.DateTimeOffset;publicoverrideobjectToDbValue(TypefieldType,objectvalue){varinstantValue=(Instant)value;returninstantValue.ToDateTimeOffset();}publicoverrideobjectFromDbValue(TypefieldType,objectvalue){returnInstant.FromDateTimeOffset((DateTimeOffset)value);}}SqlServerDialect.Provider.RegisterConverter<Instant>(newSqlServerInstantConverter());In DATETIME2 in UTC:
publicclassSqlServerInstantDateTimeConverter:OrmLiteConverter{publicoverridestringColumnDefinition=>"DATETIME2";publicoverrideDbTypeDbType=>DbType.DateTime;publicoverrideobjectToDbValue(TypefieldType,objectvalue){varinstantValue=(Instant)value;returninstantValue.ToDateTimeUtc();}publicoverrideobjectFromDbValue(TypefieldType,objectvalue){vardateTime=DateTime.SpecifyKind((DateTime)value,DateTimeKind.Utc);returnInstant.FromDateTimeUtc(dateTime);}}SqlServerDialect.Provider.RegisterConverter<Instant>(newSqlServerInstantDateTimeConverter());See the SQL Server Types wiki for how to enable support for SQL Server-specific SqlGeography, SqlGeometry and SqlHierarchyId Types.