Having more than one entity context

asp.net-core asp.net-core-mvc entity-framework-core

Question

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 ?

Edit...

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.

Edit 2 ...

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.

Edit 3 ...

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...

Edit 4 ...

https://github.com/aspnet/DependencyInjection/issues/352

Accepted Answer

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.:

  1. 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)) { ...

  2. 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:

https://github.com/aspnet/EntityFramework/issues/4441



Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why