Entity Framework with Reusable Entity Context Library

Entity Framework is one of the most powerful ORM tools in the .NET world. Entity Context Library (ECL) is a community contributed library to easily manage multiple database connection strings in a single application. In this article, I will introduce how to use ECL for a real world application.

ECL provides of four distinctive interfaces – IDbContextFactory, IRepositoryBase, IUnitOfWork and IUnitOfWorkManager. Let’s assume that we have a database containing Products table and its database connection string named as ApplicationDbContext.

CREATE TABLE Products (
    Id          AS INT,
    Name        AS NVARCHAR(256),
    Description AS NVARCHAR(256),
    Price       AS DECIMAL(18, 2)
)
`</pre>

This can be modelled by Code First Approach like:

<pre>`public class ApplicationDbContext : DbContext
{
    static ApplicationDbContext()
    {
        Database.SetInitializer&lt;ApplicationDbContext&gt;(null);
    }

    public ApplicationDbContext()
        : base("Name=ApplicationDbContext")
    {
    }

    public IDbSet&lt;Product&gt; Products { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
}
`</pre>

## `IDbContextFactory`

`IDbContextFactory` interface provides a simple interface to return a `DbContext` instance based on type. This can be useful when multiple database connection strings are used in one application. Here's a sample code snippet, assuming [`Autofac`](http://autofac.org) is used together, as an IoC container.

<pre>`using Autofac;
...

public static class Program
{
  private const string SERVICE_NAME = "MyService";

  public static void Main(string[] args)
  {
    var builder = new ContainerBuilder();

    // Register ApplicationDbContext with DbContextFactory.
    builder.RegisterType&lt;DbContextFactory&lt;ApplicationDbContext&gt;&gt;()
           .Named&lt;IDbContextFactory&gt;(SERVICE_NAME)
           .As&lt;IDbContextFactory&gt;();

    ...

    _container = builder.Build();
  }
}

`</pre>

## `IRepositoryBase`

`IRepositoryBase` interface provides a basic CRUD methods for each repository representing a table in a database. Therefore, each repository can just inherit the base repository class and use it. In addition to this, all methods like `Get`, `Add`, `Update` and `Delete` methods are overrideable, so you can redefine your way of `SELECT`, `INSERT`, `UPDATE` and `DELETE` actions.

With `Products` details above, we can create `ProductRepository` class like this:

<pre>`public interface IProductRepository : IRepositoryBase&lt;Product&gt;
{
  // You can put as many methods as you want here.
}

public class ProductRepository : RepositoryBase&lt;Product&gt;, IProductRepository
{
  public ProductRepository(IDbContextFactory contextFactory)
    : base(contextFactory)
  {
  }

  // You can here implement methods defined in the interface above. 
}
`</pre>

You can put a line of code into the `Autofac` IoC container:

<pre>`// Register ProductRepository.
builder.Register(p =&gt; new ProductRepository(p.ResolveNamed&lt;IDbContextFactory&gt;(SERVICE_NAME)))
       .As&lt;IProductRepository&gt;();
`</pre>

## `IUnitOfWorkManager`

`IUnitOfWorkManager` interface only provides one method, `CreateInstance` to create and dispose `UnitOfWork` instance. With `Autofac`, you can put a line of code into the IoC container:

<pre>`// Register UnitOfWorkManager.
builder.Register(p =&gt; new UnitOfWorkManager(p.ResolveNamed&lt;IDbContextFactory&gt;(SERVICE_NAME)))
       .As&lt;IUnitOfWorkManager&gt;();
`</pre>

## `IUnitOfWork`

`IUnitOfWork` interface handles database transactions for `INSERT`, `UPDATE` and `DELETE`. Therefore it provides transaction related methods like `BeginTransaction`, `SaveChanges`, `Commit` and `Rollback`. You can use this within your database access layer like:

<pre>`public interface ProductQueryManager
{
  bool Add(Product product);
  bool Update(Product product);
  bool Delete(Product product);
}

// ProductQueryManager performs INSERT/UPDATE/DELETE actions.
public class ProductQueryManager
{
  private readonly IUnitOfWorkManager _uowm;
  private readonly IProductRepository _product;

  public ProductQueryManager(IUnitOfWorkManager uowm, IProductRepository product)
  {
    if (uowm == null)
    {
      throw new ArgumentNullException("uowm");
    }
    this._uowm = uowm;

    if (product == null)
    {
      throw new ArgumentNullException("product");
    }
    this._product = product;
  }

  // Adds a product into the table.
  public bool Add(Product product)
  {
    using (var uow = this._uowm.CreateInstance&lt;ApplicationDbContext&gt;())
    {
      uow.BeginTransaction();

      try
      {
        this._productRepository.Add(product);
        uow.Commit();
        return true;
      }
      catch (Exception ex)
      {
        uow.Rollback();

        //
        // Do some error handling logic here.
        //

        return false;
      }
    }
  }

  // Updates a product on the table.
  public bool Update(Product product)
  {
    using (var uow = this._uowm.CreateInstance&lt;ApplicationDbContext&gt;())
    {
      uow.BeginTransaction();

      try
      {
        this._productRepository.Update(product);
        uow.Commit();
        return true;
      }
      catch (Exception ex)
      {
        uow.Rollback();

        //
        // Do some error handling logic here.
        //

        return false;
      }
    }
  }

  // Deletes a product from the table.
  public bool Delete(Product product)
  {
    using (var uow = this._uowm.CreateInstance&lt;ApplicationDbContext&gt;())
    {
      uow.BeginTransaction();

      try
      {
        this._productRepository.Delete(product);
        uow.Commit();
        return true;
      }
      catch (Exception ex)
      {
        uow.Rollback();

        //
        // Do some error handling logic here.
        //

        return false;
      }
    }
  }
}
`</pre>

This `ProductQueryManager` can be put toegher with the `Autofac` IoC container.

<pre>`builder.RegisterType&lt;ProductQueryManager&gt;().As&lt;IProductQueryManager&gt;();

Conclusion

So far, we have took a time to look at ECL with simple usage. As what IoC container does, we don’t have to worry about how data is stored or retrieved. With ECL we don’t even have to worry about multiple database connections for transactions. What we need to focus is just to implement business logic in separate classes.