Property Handlers
This feature allows you to handle the transformation of class properties and database columns (inbound/outbound). It enables custom conversion between class properties and .NET CLR types.
Each transformation execution receives the actual value and the affected ClassProperty object for additional context.
The following objects are used:
| Object | Description |
|---|---|
| IPropertyHandler | An interface to mark your class as a property handler. |
| PropertyHandler | An attribute used to map a property handler to a specific property. |
| PropertyHandlerMapper | A mapper used to map a property handler to a specific property. |
| FluentMapper | A fluent mapper class used to map a property handler to a specific property. |
Relevant Use-Cases
Common scenarios that this feature addresses:
| Use-Case | Description |
|---|---|
| String to Complex-Type | Convert an NVARCHAR column named Address to and from an Address class within the application. |
| As Type Handler | Convert the Kind property of System.DateTime each time a record is pushed or pulled from the database. |
Additional use cases include:
- Overriding the conversion of monetary columns to a specific .NET type.
- Querying related child records of parent rows.
- Triggering updates as a reaction to transformation.
- Using as a trigger mechanism.
- Manually overriding the default handler for enumerations.
- And many more.
How does it works?
When reading data from the database (e.g., ExecuteQuery, Query, BatchQuery), the Get() method is invoked after deserializing the model property. When pushing data to the database (e.g., Insert, Merge, Update), the Set() method is invoked before the actual database operation.
Implementing a Property Handler
Create a class that implements the IPropertyHandler interface.
public class PersonAddressPropertyHandler : IPropertyHandler<string, Address>
{
public Address Get(string input, PropertyHandlerGetOptions options) =>
!string.IsNullOrEmpty(input) ? JsonConvert.Deserialize<Address>(input) : null;
public string Set(Address input, PropertyHandlerSetOptions options) =>
(input != null) ? JsonConvert.Serialize(input) : null;
}
The handler above converts a string column to a class object and back.
Attaching to a Property
Use the PropertyHandler attribute to attach a property handler to a class property.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
[PropertyHandler(typeof(PersonAddressPropertyHandler))]
public Address Address { get; set; }
}
Or use the FluentMapper class, which uses PropertyHandlerMapper internally.
FluentMapper
.Entity<Person>()
.PropertyHandler<PersonAddressPropertyHandler>(e => e.Address);
When calling pull operations (e.g., Query, QueryAll, BatchQuery), the Get() method is invoked.
When calling push operations (e.g., Insert, Update, Merge), the Set() method is invoked.
Please visit our Property Handler (Property Level) reference implementation page for the detailed implementation.
Creating a Type-Level Property Handler
The implementation follows the same process as Implementing a Property Handler. Create a class that implements the IPropertyHandler interface.
public class DateTimeKindToUtcPropertyHandler : IPropertyHandler<DateTime?, DateTime?>
{
public DateTime? Get(DateTime? input, PropertyHandlerGetOptions options) =>
DateTime.SpecifyKind(input, DateTimeKind.Utc);
public DateTime? Set(DateTime? input, PropertyHandlerSetOptions options) =>
DateTime.SpecifyKind(input.GetValueOrDefault(), DateTimeKind.Unspecified);
}
Use the PropertyHandlerMapper class to map it:
PropertyHandlerMapper.Add(typeof(DateTime), new DateTimeKindToUtcPropertyHandler(), true);
Or use the FluentMapper class for type-level mapping, which also uses PropertyHandlerMapper internally.
FluentMapper
.Type<DateTime>()
.PropertyHandler<PersonAddressPropertyHandler>();
Please visit our Property Handler (Type Level) reference implementation page for the detailed implementation.