Let's say I've extended identity framework
dbContext to build my own, and I've our authenticated controller who get injected with the
dbContext and fetch an entity related with the current
ApplicationUser, entity framework will relate the two entities leading to a server error because of circular references.
We don't want to serialize circular references.
So we create a new
dbContext in the method who istantiate a new
dbcontext and query the unrelated entities, this will work. But this is not testable, we don't want our controller to strictly depends on the
dbContext, we want it to be injected.
So we add a second parameter, in the constructor, unfortunately this will make the system inject the same
dbContext twice, not so useful.
We tried to create a class
fakeDbContext who inherit from
dbContext and add it services and use it, but now we got two dbcontext, who can potentially generate migrations and configurations and errors...
Which is the right way of doing this in the new MVC6 ?
I found out that if my controller require an
IEnumerable<dbContext> i get all the object registered as service of that type, so just doubling the part in startup.cs where we add the
dbContext in the service registration area i get two of them...
The drawback here is that i don't know wich one is the virgin one, it looks like it goes in order of registration, but i have no clue, if this will change.
I've created a
TransientDbService class who have just a factory method taking the
IserviceProvider, it use it to get the options to construct the
dbContext, and then expose it. I've registered it as transient, then in the controller i require this service type.
the drawback here is if i'll ever need a third
dbContext i should write more code, more code means errors and maintaning it.
Not having two dbContext at all. The following setting allow me to have no relationships valorized.
Database.ChangeTracker.QueryTrackingBehavior = Microsoft.Data.Entity.QueryTrackingBehavior.NoTracking;
The drawback here is that i can't use my model graph, making everything more complex...
You are right to think that no tracking queries will help in some cases, but other times you'll need to have more than one instance of the DbContext created.
You normally use the
AddDbContext<TContext>() method in startup to make sure an instance of your context type is created per request and the right
DbContextOptions and service provider get set on it. When you need to deviate from this pattern you have a few options, e.g.:
Include a constructor in your derived DbContext class that takes an
IServiceProvider and passes it to the base constructor. Make sure your controller takes
IServiceProvider. Once you do this you should be able to create
DbContext manually with something like this:
using(var context1 = new MyDbContext(serviceProvider),
var context2 = new MyDbContext(serviceProvider))
To avoid having to change the constructor signatures on your derived
DbContext type you can take advantage of the
DbContextActivator class (it is our Internal namespace), e.g.:
using(var context1 = DbContextActivator.CreateInstance<MyDbContext>(serviceProvider),
var context2 = DbContextActivator.CreateInstance<MyDbContext>(serviceProvider)
Note: If you are still using
AddDbContext<MyDbContext>(options => ...) in startup it should pull those options automatically from the service provider. But you can also choose to either include the
DbContextOptions as a parameter in the constructor or override the
OnConfiguring() method for that.
I am giving you examples that create two separate
DbContexts in a using block, but you should also be able to mix those with the regular "per-request" DbContext you would get injected in the controller's constructor.
Besides these options currently available I have created a new issue to track other possible improvements on how to create multiple instance of the same
DbContext type in the same request: