Skip to content

Latest commit

 

History

History
258 lines (198 loc) · 9 KB

v1.13.0.md

File metadata and controls

258 lines (198 loc) · 9 KB

RepoDB (v1.13.0)

We are happy to share what's the highlights on our release v1.13.0. This release note corresponds to the library's release tag v1.13.0.

Trace Feature Refactoring (Breaking Changes)

In this release, we have refactored how the tracing has been implemented. The user story can be found here. This is a breaking changes!

The interface ITrace method has been simplified. There will only be 4 methods available moving forward.

Method Description
BeforeExecution Triggered before the actual database operation is being executed.
AfterExecution Triggered after the actual database operation has been executed.
BeforeExecutionAsync Triggered before the actual database asynchronous operation is being executed.
AfterExecutionAsync Triggered after the actual database asynchronous operation has been executed.

All operations will be having an optional traceKey argument. By default, the value of the traceKey is the name of the operation itself. The list can be found in the TraceKeys class.

Let us say have created the trace class below.

public class ApplicationTracer : ITrace
{
    public void BeforeExecution(CancellableTraceLog log)
    {
        throw new NotImplementedException();
    }

    public void AfterExecution<TResult>(ResultTraceLog<TResult> log)
    {
        throw new NotImplementedException();
    }

    public Task BeforeExecutionAsync(CancellableTraceLog log,
        CancellationToken cancellationToken = default)
    {
        throw new NotImplementedException();
    }

    public Task Task AfterExecutionAsync<TResult>(ResultTraceLog<TResult> log,
        CancellationToken cancellationToken = default)
    {
        throw new NotImplementedException();
    }
}

See below the sample code when calling the Insert operation.

var user = GetNewlyRegisteredUser();
var result = connection.Insert<User>(user, traceKey: TraceKeys.Insert, trace: new ApplicationTracer());

You can now allow to pass any value to the traceKey argument.

var user = GetNewlyRegisteredAdminUser();
var result = connection.Insert<User>(user, traceKey: "InsertAdminUser", trace: new ApplicationTracer());

Then, capture the information of the operation and do something else within your trace class before the actual execution.

public void BeforeExecution(CancellableTraceLog log)
{
    Logger.Log($"SessionId: {log.SessionId}, Statement: {log.Statement}, Parameters: {log.Parameter.AsJson()}")

    if (log.Key == TraceKey.Insert)
    {
        // Do something for 'Insert'
    }
    else if (log.Key == "InsertAdminUser")
    {
        // Do something for 'InsertAdminUser'
    }
    else
    {
        // Cancel and throw the exception
        log.Cancel(true);
    }
}

And also, do further actions upon completion.

public void AfterExecution<TResult>(ResultTraceLog<TResult> log)
{
    Logger.Log($"SessionId: {log.SessionId}, ExecutionTime: {log.ExecutionTime.TotalMilliseconds}, Result: {log.Result.AsJson()}")

    if (log.Key == TraceKey.Insert)
    {
        // Do something for 'Insert'
    }
    else if (log.Key == "InsertAdminUser")
    {
        // Do something for 'InsertAdminUser'
    }
}

Note: Both methods BeforeExecution and AfterExecution will be invoked when you call any operation of the library.

You can visit our official documentation regarding Tracing for futher information.

Global Configuration

In this release, we have introduced the class named GlobalConfiguration to help simplify the library global initialization.

This has deprecated the existing bootstrapper methods of the extended libraries.

By having this class, it enable the developers to specify the optional settings during the initialization.

GlobalConfiguration
    .Setup(new()
    {
        ConversionType = ConversionType.Default,
        DefaultBatchOperationSize = Constant.DefaultBatchOperationSize,
        DefaultCacheItemExpirationInMinutes = Constant.DefaultCacheItemExpirationInMinutes,
        EnumDefaultDatabaseType = DbType.String,
        KeyColumnReturnBehavior = KeyColumnReturnBehavior.IdentityOrElsePrimary
    })
    .UseSqlServer();

The Setup() method is required but it accepts an optional instance of GlobalConfigurationOptions class.

Note: In the code above, it calls the UseSqlServer() method to initialize the components for SQL Server. You have to call the corresponding method for the other RDBMS data provider.

Multiple Query Caching

In this release, we have introduced the caching to both the QueryMultiple and ExecuteQueryMultiple method.

Let us say you have implemented the cacher class below.

public class ApplicationCacher : ICache
{
    ...
}

Then, you can now start passing this class to the QueryMultiple method.

var applicationCacher = GetApplicationCacherSingletonInstance(); // Returns a singleton instance of ApplicationCacher

var (customers, orders) = connection.QueryMultiple<Customers, Orders>(c => c.Id == customerId,
    o => o.CustomerId == customerId,
    cacheKey1: $"Customer-{customerId}",
    cacheKey2: $"Customer-{customerId}-Orders",
    cache: applicationCacher);

And also to the ExecuteQueryMultiple method.

var applicationCacher = GetApplicationCacherSingletonInstance(); // Returns a singleton instance of ApplicationCacher

var extractor = connection.ExecuteQueryMultiple("SELECT * FROM [dbo].[Customer] WHERE [Id] = @CustomerId; SELECT * FROM [dbo].[Order] WHERE [CustomerId] = @CustomerId;",
    new { CustomerId = customerId },
    cacheKey: $"Customer-{customerId}",
    cache: applicationCacher);

Property/Class Handlers (Breaking Changes)

In this release, both the IPropertyHandler and IClassHandler will now be having the an option classes as the second argument to every method.

See below for the property handler.

public class AddressPropertyHandler : IPropertyHandler<string, Address>
{
    public Address Get(string input, PropertyHandlerGetOptions options)
    {
        // Handle the transformation from the DB towards the Class
    }

    public string Set(Address input, PropertyHandlerSetOptions options)
    {
        // Handle the transformation from the Class towards the DB
    }
}

And below is for the class handler.

public class PersonClassHandler : IClassHandler<Person>
{
    public Person Get(Person input, ClassHandlerGetOptions options)
    {
        // Handle the Class before sending back to the caller
    }

    public string Set(Person input, ClassHandlerSetOptions options)
    {
        // Handle the Class before sending to DB
    }
}

Please feel free to visit the official documentation of IPropertyHandler and IClassHandler for more information.

ICache Async Methods (Breaking Changes)

In this release, we have introduced all the corresponding asynchronous methods of the ICache interface.

See below the sample code.

public class JsonCache : ICache
{
    public void Add<T>(string key,
        T value,
        int expiration = 180,
        bool throwException = true)
    {
        ...
    }

    public Task AddAsync<T>(string key,
        T value,
        int expiration = 180,
        bool throwException = true,
        CancellationToken cancellationToken = default)
    {
        ...
    }

    public void Clear()
    {
        ...
    }

    public void ClearAsync(CancellationToken cancellationToken = default)
    {
        ...
    }

    ...
}

Please visit our actual release page to see the updates.