In an ASP.Net 7 web api application, we have two sets of entities we need to build up with one set being built and persisted to the database, and the other set of entities being built in memory, but then discarded without persisting them so that we can preview the changes without saving. Both of these sets of entities are in the same database. We are using dependency injection to inject a DbContext into the controller when the controller is instantiated. In order to have separate "save contexts" such that one set of entities may be built without saving them while objects in the other "save contexts", I attempted to inject two instances of same DbContext into the controller.
public MyController(MyDbContext dbContext1, MyDbContext dbContext2)...
However, when I make changes to dbContext1 and the run dbContext1.SaveChanges(), I would expect that only the entities that I create and attach to dbContext1 are persisted, but what I have found is that the entities in dbContext2 are also persisted even though they are in a different instance of the DbContext.
public class MyController{
MyDbContext _dbContext1;
MyDbContext _dbContext2;
public MyController(MyDbContext dbContext1, MyDBContext dbContext2){
_dbContext1 = dbContext1;
_dbContext2 = dbContext2;
}
[HttpPost]
public async Task<IActionResult> AddAsync(MyEntity myEntity)
{
_dbContext1.MyEntities.Add(myEntity); // DO NOT want this entity saved
_dbContext2.MyEntities.Add(new MyEntity()); // DO want this entity saved
// Running this SaveChanges persists entities in both _dbContext1 and _dbContext2
// which is NOT what we want. We want only _dbContext2 entities to be saved
await _dbContext2.SaveChangesAsync();
}
}
How do I maintain two separate sets of entities such that a save in one does not trigger a save in the other DbContext?
Can I still use dependency injection to do that, or do I have to manually manage the DbContexts?
Do I somehow use transactions within the same DbContext to manage different sets of entities?
2
Answers
Both
_dbContext1
and_dbContext2
are the same instance. EF’s defaultDbContext
service-factory only creates a singleDbContext
instance per request-scope, and that instance is shared by all objects that use an injectedDbContext
in that same request scope.If you want multiple DbContexts you need to use
IDbContextFactory<MyDbContext>
– and you will also need to manage the lifetime of those DbContexts yourself (all you need is ausing()
block) as ASP.NET will not clean-up any DbContexts created via a factory.Change your code to this:
So without diving into WHY do you want to do this (I sense some XY Problem going on here) from pure technical standpoint of view one of the solutions would be using
IDbContextFactory
. To do that you will need to set it up in the DI:And then inject into the controller:
Notes:
AddDbContextFactory
allows resolving the context itself, so you can follow different patterns for different cases:AddDbContext
) or use change tracker to clear the changes (dbContext1.ChangeTracker.Clear();
) but without understanding WHY it is hard to tell what would be the best one.