3

I have created an application (net core 2 & ef core) with Unit Of Work and Generic repository pattern. I used to have one database context but due to some business logic I had to create a second database with some same entities.

For the sake of simplicity, I will use only one Entity, the ProductEntity and I will use only 1 repository method the Get by Id.

In the business logic I must be able to retrieve the Product from the two contexts, do some stuff and then update the contexts, but with a clean UoW design.

The repository is implemented like this

public interface IRepository<TEntity>
    where TEntity : class, new()
{      
    TEntity Get(int id);     
}

public interface IProductsRepository : IRepository<ProductEntity>
{

}

public class ProductsRepository : Repository<ProductEntity>, IProductsRepository
{
    public ProductsRepository(DbContext context) : base(context)
    {

    }
}

Implementation of UOW with one db context

public interface IUnitOfWork : IDisposable
{
    IProductsRepository ProductsRepository { get; }
    int Complete();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly DbContext _context;

    public UnitOfWork(MainContext context)
    {
        // injecting the main database
        _context = context;
    }

    private IProductsRepository _productsRepository;
    public IProductsRepository ProductsRepository => _productsRepository ?? (_productsRepository = new ProductsRepository(_context));

    public int Complete()
    {
        return _context.SaveChanges();
    }

    public void Dispose()
    {
        _context?.Dispose();
    }
}

I am using the default framework of .NET Core for DI, so at my Startup.cs file I have the following

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // ...

    // main database 
    services.AddDbContext<MainContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MainDatabaseConnection"), providerOptions => providerOptions.CommandTimeout(30)));

    // unit of work            
    services.AddTransient<IUnitOfWork, UnitOfWork>();
}

To solve the problem I have created a second UnitOfWork with hardcoded context and I am using the same entities/repositories

My implementation with two db contexts

public interface IUnitOfWorkSecondary : IDisposable
{
    IProductsRepository ProductsRepository { get; }
    int Complete();
}

public class UnitOfWorkSecondary : IUnitOfWorkSecondary
{
    private readonly DbContext _context;

    public UnitOfWork(SecondaryDatabaseContext context)
    {
        // injecting the secondary database
        _context = context;
    }

    // same as above
}

So in a business object I am doing the following

public class Program
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IUnitOfWorkSecondary _unitOfWorkSecondary;

    public Program(IUnitOfWork unitOfWork, IUnitOfWorkSecondary unitOfWorkSecondary){
        _unitOfWork = unitOfWork;
        _unitOfWorkSecondary = unitOfWorkSecondary;
    }

    public static void Method1(int productId)
    {        
        var mainProduct = _unitOfWork.ProductsRepository.Get(productId);
        var secondaryProduct = _unitOfWorkSecondary.ProductsRepository.Get(productId);

        mainProduct.Name = "Hello Main";
        secondaryProduct.Name = "Hello Secondary";

        _unitOfWork.Complete();
        _unitOfWorkSecondary.Complete();
    }    
}

The Startup.cs is modified to

// main database 
services.AddDbContext<MainContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MainDatabaseConnection"), providerOptions => providerOptions.CommandTimeout(30)));

// secondary database
services.AddDbContext<SecondaryContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SecondaryDatabaseConnectiont"), providerOptions => providerOptions.CommandTimeout(30)));

// unit of work            
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddTransient<IUnitOfWorkSecondary , UnitOfWorkSecondary>();

My questions

  1. What is the best (or most practical) design for this
  2. What if the databases are more than 2 ?
  • transaction scope works across databases stackoverflow.com/questions/22512450/… – Ewan Aug 31 '18 at 7:27
  • Sorry, this is not the case. I do not need a transaction, but an architectural solution on multiple database context and Unit Of Work pattern. – Dimitris Jan 24 at 15:26
  • ? not sure why you think transaction scope does not neatly turn your two DB Context changes into one UoW – Ewan Jan 24 at 15:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.