Search code examples
c#asp.net-coreentity-framework-coredbcontextunit-of-work

Unit of work with DBContextFactory vs DBContext


I want to implement the Unit of Work pattern in ASP.NET Core & EF Core.

My question is whether to use the DbContextFactory or DbContext instance in the unit of work constructor. Which approach is better and why?

Code sample - using DbContextFactory:

public sealed class UnitOfWork : IUnitOfWork
{
    private AppDbContext _dbContext;
    
    public UnitOfWork(IContextFactory contextFactory)
    {
        _dbContext = contextFactory.DbContext;
    }
}

Using DbContext:

public sealed class UnitOfWork : IUnitOfWork
{
    private AppDbContext _dbContext;
    
    public UnitOfWork(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }
}

While Entity Framework Core's DbContext can be considered a unit of work in the context of managing database operations, I want to implement my own unit of work pattern for managing feature plans.


Solution

  • If you don't plan on using pooled DbContext factory (serices.AddPooledDbContextFactory(options => ...), you should just inject DbContext (or better your actual class deriving from it) into your services.

    This is easier as the dependency injection will will do all the instantiation and disposing at the end of the scope (by default end of the request).

    If you intend or plan to use AddPooledDbContextFactory in future, you should use the factory. But be aware, that then it's also your task to dispose it. For that your IUnitOfWork would have to implement IDisposable too

    public sealed class UnitOfWork : IUnitOfWork, IDisposable
    {
        private AppDbContext _dbContext;
        private bool disposing;
        
        public UnitOfWork(IContextFactory contextFactory)
        {
            _dbContext = contextFactory.DbContext;
        }
    
        public virtual Dispose(bool disposing)
        {
            if (disposing)
            {
                _dbContext?.Dispose();
            }
        }
    
        public sealed void Dispose()
        {
            GC.SupressFinalizer(this);
            Dispose(true);
        }
    }
    

    To ensure that memory is released as soon as possible. When using DbContext directly outside of a repository, you should releasing it as soon as you are finished dealing with it, rather than at the end of the request

    using(DbContext dbContext = contextFactory.CreateContext())
    {
        // Do your DbContext operations here
    }
    // dbContext is disposed and memory released
    ...
    // Do other work here