I was not able to come up with a method to reset the global DbContext. I was able to solve my problem, however, by injecting a DbContextLocator
into any class that needs a DbContext instead of passing the DbContext itself.
My goal was to maintain a global DbContext, but allow it to be reset whenever needed (such as after a database rebuild or import).
My solution uses an abstract base class and a concrete class.
Base Class
using System.Data.Entity;
namespace CommonLibrary.Database
{
public abstract class DbContextLocator
{
private DbContext _dbContext;
public DbContext Current
{
get { return _dbContext; }
}
public DbContextLocator()
{
_dbContext = GetNew();
}
public virtual void Reset()
{
_dbContext.Dispose();
_dbContext = GetNew();
}
protected abstract DbContext GetNew();
}
}
Concrete Class
using System.Data.Entity;
using CommonLibrary.Database;
using ExperimentBase.EntityModels;
namespace MainProject.Models
{
public class MainDbContextLocator : DbContextLocator
{
public new MainDbContext Current
{
get { return (MainDbContext)base.Current; }
}
protected override DbContext GetNew()
{
return new MainDbContext();
}
}
}
Usage
Get the current DbContext:
var dbContext = dbContextLocator.Current;
Reset the DbContext:
dbContextLocator.Reset();
//Note: normally followed by code that re-initializes app data
Edit
Based on Shimmy's feedback, I made DbContextLocatorBase
into a generic. (I'm also now implementing IDisposable
.)
Base Class
public class DbContextLocator<TContext> : IDisposable
where TContext : DbContext, new()
{
private TContext _dbContext;
public TContext Current
{
get { return _dbContext; }
}
public DbContextLocator()
{
_dbContext = GetNew();
}
public virtual void Reset()
{
_dbContext.Dispose();
_dbContext = GetNew();
}
protected virtual TContext GetNew()
{
return new TContext();
}
public void Dispose()
{
_dbContext.Dispose();
}
}
Concrete Class (optional, since the base class is no longer abstract)
public class MainDbContextLocator : DbContextLocator<MainDbContext> { }