Preparing for Dapper (Summary)

A new "core architecture" has been defined for the team. IDbDataContext and DbRepositoryBase are designed to shield the applications from the data source and from the underlying technologies of the data layer. As far as the applications are concerned, they know only of the POCOs and the repositories.

In usage, the application ends up with something like this to search:

    using (POCONameRepository r = new POCONameRepository())
    {
        // prepare the parameters...
        IEnumerable<POCOname> result = r.Search(...);
        // evaluate return values...
        return result;
    }
And for CRUD:

    using (POCONameRepository r = new POCONameRepository())
    {
        // prepare the parameters...
        //POCOName model = r.Create(...);
        POCOName model = r.Read(...);
        //POCOName model = r.Update(...);
        //POCOName model = r.Delete(...);
        // evaluate return values...
        return model;
    }
For the keen eyed, you should see that there's a problem, particularly with the database context. If you try implementing DbDataContextBase and use it in your DbRepositoryBase repository, you should find that there's no way to pass the database connection string. This should've been the purpose of the abstract method DbDataContextBase.BuildContext(). However, it does not accept any parameter. What's happening here, Mendz?!

The team wants the application to be so unaware of the database context that I decided for the database context to be self-initializing, although it does so within the context of the current active domain. So, I do the following in my BuildContext() implementation.

public class TestDbDataContext : DbDataContextBase
{
    protected override IDbConnection BuildContext()
    {
        return new SqlConnection(
            ConnectionStringOptions.Instance["TestDB"]);
    }
}
This code implements DbDataContextBase, which requires that the abstract method BuildContext() is implemented. In my BuildContext() implementation, it uses a singleton called ConnectionStringOptions, which Instance is an indexer to a list of connection strings. The ConnectionStringOptions should be initialized in the application's startup. This is the closest that the application can get to directly knowing anything about the database context. The approach I used made sure that the database context is not initializing on its own. It needs the domain to set the ConnectionStringOptions, thus the database context can only really initialize within an active domain.

The goals are clear and these designs deliver to the dot. The team has experience enough with stored procedures to know that all business logic and rules can reside in them. The application can be totally unaware of the data sources. Finally, the repositories are flexible enough to allow for developer creativity and innovation.
  1. Preparing for Dapper (Part 1) - Business logic and rules in one place
  2. Preparing for Dapper (Part 2) - POCOs
  3. Preparing for Dapper (Part 3) - The database context
  4. Preparing for Dapper (Part 4) - The repository base
Compared to my experience 10 years ago, the new "core architecture" took a very a short time to complete. Dapper's built-in data mapper features particularly helped a lot. Its bare approach to add extensions to ADO.Net also made it easy for me to create my own version of the database context. The materials all over the web about repositories plus the team's own experience in creating business objects likewise led me to designing a very basic "repository". Out of all these efforts, the templates and guidelines were easily put together and shared to the developers in order to jumpstart them in to the project at hand. The new "core architecture" is designed to immediately promote productivity and quality delivery -- evolution and maturity later.

Comments