Why Re-Initiate the Dbcontext When Using the Entity Framework

Why re-initiate the DbContext when using the Entity Framework?

Managing Lifetime

You're correct that a single static instance of DbContext is usually not recommended:

The more you use an ObjectContext, generally the bigger it gets.
This is because it holds a reference to all the Entities it has ever
known about, essentially whatever you have queried, added or attached.
So you should reconsider sharing the same ObjectContext indefinitely.

These comments apply directly to the DbContext, because it wraps wraps ObjectContext to expose "simplified and more intuitive APIs." [see documentation]


Cost of Construction

The overhead of creating the context is relatively low:

The reality is this cost is actually pretty low, because mostly it
simply involves copying, by reference, metadata from a global cache
into the new ObjectContext. Generally I don’t think this cost is worth worrying about ...

The common way to work with a short-lived context is to wrap it in a using block:

using(DbContext context = new SomeDbContext())
{
// Do work with context
}

To ease with testing, you may want to have your DbContext implement some IDbContext interface, and create a factory class ContextFactory<T> where T : IDbContext to instantiate contexts.

This allows you to easily swap any IDbContext into your code (ie. an in-memory context for object mocking.)


Resources

  • MSDN: How to decide on a lifetime for your ObjectContext
  • StackOverflow: Instantiating a context in LINQ to Entities

How to refresh an Entity Framework Core DBContext?

Dependency Injection and DbContext

You mention that when you try to recreate your DbContext, you get an error about the context being managed by your dependency injection (DI) system. There are two different styles of using a dependency injection system for object creation. The DI can either create a global singleton instance that is shared as a service between all consumers or it can create an instance per scope/unit of work (e.g., per request in a web server).

If your DI system is configured to create a single global shared instance of DbContext, then you will encounter various problems associated with long-lived DbContext.

  • DbContext, by design, never automatically removes objects from its cache because it is not designed to be long-lived. Thus, a long-lived DbContext will retain memory wastefully.
  • Your code will never see changes to items loaded into its cache without manually reloading each entity it loads.
  • DbContext only allows one query to run at any time and is not threadsafe. If you try to run multiple queries on a globally shared instance, it will throw DbConcurrencyException (at least on its async interface, not sure about its sync interface).

Thus, the best practice is to use a single DbContext per unit of work. Your DI system can help you with this by being configured to provide a fresh instance for each request your application processes within a scope. For example, ASP.NET Core’s Dependency Injection system supports scoping instances by request.

Refreshing a Single Entity

The easiest way to get fresh data is to create a new DbContext. However, within your unit of work, or within the constraints of the granularity of scoping provided by your DI system, you may trigger an external process which is supposed to modify your entity directly in the database. You may need to see that change before exiting your DI’s scope or completing your unit of work. In that case, you can force a reload by detaching your instance of the data object.

To do this, first get the EntityEntry<> for your object. This is an object which lets you manipulate DbContext’s internal cache for that object. You can then mark this entry detached by assigning EntitytState.Detached to its State property. I believe that this leaves the entry in the cache but causes the DbContext to remove and replace it when you actually load the entry in the future. What matters is that it causes a future load to return a freshly loaded entity instance to your code. For example:

var thing = context.Things.Find(id);
if (thing.ShouldBeSentToService) {
TriggerExternalServiceAndWait(id);

// Detach the object to remove it from context’s cache.
context.Entities(thing).State = EntityState.Detached;

// Then load it. We will get a new object with data
// freshly loaded from the database.
thing = context.Things.Find(id);
}
UseSomeOtherData(thing.DataWhichWasUpdated);

Is there a way to reset a DbContext without disposing and reinstantiating it?

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> { }

How to instantiate a DbContext in EF Core

Note


At the time of writing the use of EF Core with the Dependency injection framework wasn't as known as it is now. This answers gives answer to the question from a DI perspective, which at the time, helped out OP.

The other answer provides you a conventional way to instantiate the DbContext using the new operator.



TL;DR, 3 options:

Option 1

Register the DbContext during application configuration:

public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextPool<BlexzWebDb>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BlexzWebConnection")));
}

and use the DI framework to retrieve it:

public class SomeController : Controller
{
private readonly BlexzWebDb _db;

//the framework handles this
public SomeController(BlexzWebDb db)
{
_db = db;
}
}

Option 2

If you are looking for a design-time IdentityDbContext using IOptions<OperationalStoreOptions>, see: Add migration for ApiAuthorizationDbContext from another project - EF Core

Option 3

Or use the new operator and provide the details, see @Qamar Zaman's answer for details.



The long answer, and why DI is a treat

In EF Core it's common to pass some DbContextOptions to the constructor.

So in general, a constructor looks like this:

public BlexzWebDb(DbContextOptions<BlexzWebDb> options) : base(options)

As you can see there, there is no valid overload in the form of a parameter-less constructor:

Thus, this does not work:

using (var db = new BlexzWebDb())

Obviously, you can pass in an Option object in the constructor but there is an alternative. So,

Instead


.Net Core has IoC implemented in it's roots. Okay, this means; you don't create a context, you ask the framework to give you one, based on some rules you defined before.

Example: somewhere you will register your dbcontext, (Startup.cs):

//typical configuration part of .net core
public void ConfigureServices(IServiceCollection services)
{
//some mvc
services.AddMvc();

//hey, options!
services.AddDbContextPool<BlexzWebDb>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BlexzWebConnection")));
//...etc

Now the registering part is done, you can retrieve your context from the framework. E.g.: inversion of control through a constructor in your controller:

public class SomeController : Controller
{
private readonly BlexzWebDb _db;

//the framework handles this
public SomeController(BlexzWebDb db)
{
_db = db;
}

//etc.


why?

So, why not just provide the arguments and new it?

There is nothing wrong with the use of new - there are a lot of scenario's in which it works best.

But, Inversion Of Control is considered to be a good practice. When doing asp dotnet core you're likely to use it quite often because most libraries provide extension methods to use it. If you are not familiar with it, and your research allow it; you should definitely give it a try.

Therefore, instead of providing "just a way to instantiate" the object, I'll try to get you onto this track - inline with the framework. It will save you some hassle afterwards. Besides, otherwise "use an activator's CreateInstance" would just be as valid as an answer ;-)

Some links:

  • MSDN Fundamentals
  • MSDN Dependency Injection
  • Wikipedia Inversion Of Control

One DbContext per web request... why?

NOTE: This answer talks about the Entity Framework's DbContext, but
it is applicable to any sort of Unit of Work implementation, such as
LINQ to SQL's DataContext, and NHibernate's ISession.

Let start by echoing Ian: Having a single DbContext for the whole application is a Bad Idea. The only situation where this makes sense is when you have a single-threaded application and a database that is solely used by that single application instance. The DbContext is not thread-safe and since the DbContext caches data, it gets stale pretty soon. This will get you in all sorts of trouble when multiple users/applications work on that database simultaneously (which is very common of course). But I expect you already know that and just want to know why not to just inject a new instance (i.e. with a transient lifestyle) of the DbContext into anyone who needs it. (for more information about why a single DbContext -or even on context per thread- is bad, read this answer).

Let me start by saying that registering a DbContext as transient could work, but typically you want to have a single instance of such a unit of work within a certain scope. In a web application, it can be practical to define such a scope on the boundaries of a web request; thus a Per Web Request lifestyle. This allows you to let a whole set of objects operate within the same context. In other words, they operate within the same business transaction.

If you have no goal of having a set of operations operate inside the same context, in that case the transient lifestyle is fine, but there are a few things to watch:

  • Since every object gets its own instance, every class that changes the state of the system, needs to call _context.SaveChanges() (otherwise changes would get lost). This can complicate your code, and adds a second responsibility to the code (the responsibility of controlling the context), and is a violation of the Single Responsibility Principle.
  • You need to make sure that entities [loaded and saved by a DbContext] never leave the scope of such a class, because they can't be used in the context instance of another class. This can complicate your code enormously, because when you need those entities, you need to load them again by id, which could also cause performance problems.
  • Since DbContext implements IDisposable, you probably still want to Dispose all created instances. If you want to do this, you basically have two options. You need to dispose them in the same method right after calling context.SaveChanges(), but in that case the business logic takes ownership of an object it gets passed on from the outside. The second option is to Dispose all created instances on the boundary of the Http Request, but in that case you still need some sort of scoping to let the container know when those instances need to be Disposed.

Another option is to not inject a DbContext at all. Instead, you inject a DbContextFactory that is able to create a new instance (I used to use this approach in the past). This way the business logic controls the context explicitly. If might look like this:

public void SomeOperation()
{
using (var context = this.contextFactory.CreateNew())
{
var entities = this.otherDependency.Operate(
context, "some value");

context.Entities.InsertOnSubmit(entities);

context.SaveChanges();
}
}

The plus side of this is that you manage the life of the DbContext explicitly and it is easy to set this up. It also allows you to use a single context in a certain scope, which has clear advantages, such as running code in a single business transaction, and being able to pass around entities, since they originate from the same DbContext.

The downside is that you will have to pass around the DbContext from method to method (which is termed Method Injection). Note that in a sense this solution is the same as the 'scoped' approach, but now the scope is controlled in the application code itself (and is possibly repeated many times). It is the application that is responsible for creating and disposing the unit of work. Since the DbContext is created after the dependency graph is constructed, Constructor Injection is out of the picture and you need to defer to Method Injection when you need to pass on the context from one class to the other.

Method Injection isn't that bad, but when the business logic gets more complex, and more classes get involved, you will have to pass it from method to method and class to class, which can complicate the code a lot (I've seen this in the past). For a simple application, this approach will do just fine though.

Because of the downsides, this factory approach has for bigger systems, another approach can be useful and that is the one where you let the container or the infrastructure code / Composition Root manage the unit of work. This is the style that your question is about.

By letting the container and/or the infrastructure handle this, your application code is not polluted by having to create, (optionally) commit and Dispose a UoW instance, which keeps the business logic simple and clean (just a Single Responsibility). There are some difficulties with this approach. For instance, where do you Commit and Dispose the instance?

Disposing a unit of work can be done at the end of the web request. Many people however, incorrectly assume that this is also the place to Commit the unit of work. However, at that point in the application, you simply can't determine for sure that the unit of work should actually be committed. e.g. If the business layer code threw an exception that was caught higher up the callstack, you definitely don't want to Commit.

The real solution is again to explicitly manage some sort of scope, but this time do it inside the Composition Root. Abstracting all business logic behind the command / handler pattern, you will be able to write a decorator that can be wrapped around each command handler that allows to do this. Example:

class TransactionalCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
readonly DbContext context;
readonly ICommandHandler<TCommand> decorated;

public TransactionCommandHandlerDecorator(
DbContext context,
ICommandHandler<TCommand> decorated)
{
this.context = context;
this.decorated = decorated;
}

public void Handle(TCommand command)
{
this.decorated.Handle(command);

context.SaveChanges();
}
}

This ensures that you only need to write this infrastructure code once. Any solid DI container allows you to configure such a decorator to be wrapped around all ICommandHandler<T> implementations in a consistent manner.

DbSet in Entity Framework

There's no magic to this. TestDbContext is derived from DbContext

DbContext makes a call to internal class DbSetDiscoveryService which uses Reflection to iterate through DbSet properties and initialize them.

The mono version of EF, you can find the code on Github that shows the call to InitializeSets

DbContext not initializing with SQL Server Compact in ASP.Net MVC

Well after some other search on the issue, I got this MSDN forum link. As was suggested by Rowan, I tried to manually initialize the context using following statement in my EFRepository class:

dbContext.Database.Initialize(false);

The application failed way before it was hitting the GetAll() method. But this exposed the stack trace which gave me some direction:

[InvalidOperationException: Sequence contains no matching element]
System.Linq.Enumerable.Single(IEnumerable`1 source, Func`2 predicate) +2614017
System.Data.Entity.Utilities.DbProviderManifestExtensions.GetStoreTypeFromName
(DbProviderManifest providerManifest, String name) +146
.....Other Lines.....
System.Data.Entity.Internal.InternalContext.Initialize() +31
System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType
(Type entityType) +38
System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +138
System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() +38
System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable
.get_Provider() +99
System.Linq.Queryable.Any(IQueryable`1 source) +50

Then searching for DbProviderManifestExtensions.GetStoreTypeFromName revealed that this is the line where EF was trying to get column type. I had specified UNIQUEIDENTIFIER for my Id column:

Property(x=> x.Id).HasColumnType("UNIQUEIDENTIFIER")

Once I commented this, all was well.

Though there is a request on Codeplex to provide the proper error message in case the column type is not valid for database provider.

Entity Framework DbContext is initialized with wrong constructor

Disclaimer: I reproduced your code, but with one level of inheritance.

Changing

public OpContext(DbContextOptions<DbContext> options) : base(options)   { } 

to

public OpContext(DbContextOptions<OpContext> options) : base(options)   { }  

resolved the issue for me.

Notice the type argument for DbContextOptions.



Related Topics



Leave a reply



Submit