DEV Community

Mike Pendon (Zym)
Mike Pendon (Zym)

Posted on

C#: Simplify your Property Transformation with RepoDb ORM

Introduction

A property handler is a class that handles the process of property transformations. It lives in between your data model extractor (or ORM) and the actual database object (ie: Data Reader).

With this, you as a developer have the full control over the model extractor (or ORM) on how the way you would your data to be handled (read/save).

Why we need such process

There are various reasons why we need to manually override the default implementation of the data extractors.

  • Auto transform the JSON/String into Class.
  • Handle all the transformations of the specific .NET CLR Type.
  • Setting the state of the System.DateTime objects (ie: Kind).
  • Usage as trigger to something (ie: after value assignment).
  • Querying another child records.
  • and many more...

The use cases can actually be unlimited. However, such numbers will all depends on the user scenarios.

Before we begin

The programming language we will be using for this tutorial is C# and the RDBMS is SQL Server.

We expect that you already have experience working with RepoDb ORM, otherwise you can visit our Getting Started page.

In this article, we will only aim the scenario of transforming the JSON/String into a Class object.

Create the DB and Tables

CREATE DATABASE [TestDB];
GO

USE [TestDB];
GO

CREATE TABLE [dbo].[Person]
(
    [Id] BIGINT PRIMARY KEY IDENTITY(1, 1)
    , [Name] NVARCHAR(128)
    , [Age] INT
    , [ExtendedInfo] NVARCHAR(MAX)
    , [CreatedDateUtc] DATETIME2(5)
)
ON [PRIMARY];
GO

Create a C# Project

  • Type: .NET Core Console Application
  • Name: PropertyHandler

Within the project, create a folder named Models and add the class below.

public class PersonExtendedInfo
{
    public string Address { get; set; }
    public string Affiliations { get; set; }
    public string Biography { get; set; }
    public string Certifications { get; set; }
}

The class above will be used as the transformed class.

Then, add the parent class below that reference to the above class.

public class Person
{
    public long Id { get; set; }

    public string Name { get; set; }

    public PersonExtendedInfo ExtendedInfo { get; set; }

    public DateTime CreatedDateUtc { get; set; }
}

Notice the property ExtendedInfo is of type NVARCHAR from the database.

Create a Class Factory

This class is only used to create an instance of the Person class.

Add a folder named Factories and add the class below.

public static class PersonFactory
{
    public static Person Create()
    {
        return new Person
        {
            Name = $"Name-{Guid.NewGuid().ToString()}",
            Age = $"{(short)(new Random().Next(100))} years old",
            ExtendedInfo = new PersonExtendedInfo
            {
                Address = $"Address-{Guid.NewGuid().ToString()}",
                Affiliations = $"Affiliations-{Guid.NewGuid().ToString()}",
                Biography = $"Biography-{Guid.NewGuid().ToString()}",
                Certifications = $"Certifications-{Guid.NewGuid().ToString()}"
            },
            CreatedDateUtc = DateTime.UtcNow
        };
    }

    public static IEnumerable<Person> CreateMultiple(int count)
    {
        for (var i = 0; i < count; i++)
        {
            yield return Create();
        }
    }
}

Simulation

By this time, our database and C# project is now ready for use.

Install the Libaries

Type the command below within your Package Manager Console.

> Install-Package RepoDb.SqlServer
> Install-Package Newtonsoft.Json

Inside your Program.cs file follow the steps below.

Create a GetConnection method

private static SqlConnection GetConnection()
{
    return new SqlConnection("Server=.;Database=TestDB;Integrated Security=SSPI;");
}

Create an InsertPerson method

private static void InsertPerson()
{
    using (var connection = GetConnection())
    {
        var people = PersonFactory.CreateMultiple(100).AsList();
        connection.InsertAll(people);
    }
}

Create a QueryPerson method

private static void QueryPerson()
{
    using (var connection = GetConnection())
    {
        var people = connection.QueryAll<Person>();
    }
}

The methods InsertAll and QueryAll were both extended methods of IDbConnection object implemented within RepoDb.

Create a PropertyHandler

Add a folder named PropertyHandlers and add the class below.

public class PersonExtendedInfoHandler : IPropertyHandler<string, PersonExtendedInfo>
{
    public PersonExtendedInfo Get(string input,
        ClassProperty property)
    {
        return JsonConvert.DeserializeObject<PersonExtendedInfo>(input);
    }

    public string Set(PersonExtendedInfo input,
        ClassProperty property)
    {
        return JsonConvert.SerializeObject(input);
    }
}

The Get method is being called when you read a data from the database. The Set method is being called when you push a data towards the database.

Decorate the Attribute in the Property

In the Customer class, decorate the property ExtraInfo with PropertyHandlerAttribute by passing the type of your handler.

public class Person
{
    public long Id { get; set; }
    public string Name { get; set; }
    [PropertyHandler(typeof(PersonExtendedInfoHandler))]
    public PersonExtendedInfo ExtendedInfo { get; set; }
    public DateTime CreatedDateUtc { get; set; }
}

RepoDb also provides a type-level handler in which it allow the developers to handle the transformation of specific .NET CLR Type. The feature can be enabled by simply calling the PropertyTypeHandlerMapper.Add() method.

Extend the Program.Main method

static void Main(string[] args)
{
    // Intialize the RepoDb for SQL Server
    SqlServerBootstrap.Initialize();

    // Calls to the method
    ClearPerson();
    InsertPerson();
    QueryPerson();

    // Exit the console
    Console.WriteLine("Press any key to exit.");
    Console.ReadLine();
}

Testing the program

By this time, the solution is now ready for execution and testing.

  • Place a breakpoint on the Get or Set method of your Property Handler class.
  • Run the program by pressing F5

Your breakpoint will be hit and by this time you are controlling the transformation.

The actual Test project can be found here.


Remarks

Thank you for reading this tutorial. Please do not forget to share this library and star our GitHub repository.

Top comments (0)