问题
I'm working on .NET Core Web API and I have one endpoint where I want to run three operations in parallel. All three of them use the same database, so I need three copies of DbContext. I created a simple Factory class, which I later inject into my "Data" class.
Is it possible (if it's, is a good practice), to inject DbContext into my factory class (using built in .NET Core IoC) and when someone calls "CreateMyDbContext" method, just deep clone the one which was injected at the beginning?
EDIT: Here is the example with the DbContext Pool:
public class FooData : IFooData
{
private readonly Func<DisposableScopedContextWrapper> _func;
public FooData(Func<DisposableScopedContextWrapper> func)
{
_func = func;
}
public async Task<List<Apple>> GetApples()
{
using (var wrapper = _func())
{
var apples = await wrapper.Context.Apples.FromSqlRaw("SELECT.... complicated query").ToListAsync();
return apples;
}
}
public async Task<List<Orange>> GetOranges()
{
using (var wrapper = _func())
{
var oranges = await wrapper.Context.Oranges.FromSqlRaw("SELECT.... complicated query").ToListAsync();
return oranges;
}
}
}
public class FooService
{
private readonly IFooData _fooData;
public FooData(IFooData fooData)
{
_fooData = fooData;
}
public async Task<List<Fruit>> GetFruits()
{
var appleTask = _fooData.GetApples();
var orangeTask = _fooData.GetOranges();
(var result1, var result2) = await (appleTask, orangeTask).WhenAll();
// ...
}
}
回答1:
I definitely would not recommend any deepcloning for multiple reasons, one of them being that you will need to figure out a lot of EF internals to make it right, and internals can change(and you will need to spend some time on it).
Second option would be just creating your context manually, which I would recommend against also cause modern infrastructure uses DbContext
pooling.
So what you can to register Func<DbContext>
(or create your own factory) like this:
services.AddSingleton<Func<DbContext>>(provider => () =>
{
var scope = provider.CreateScope();
return scope.ServiceProvider.GetRequiredService<DbContext>();
});
the issue here is that scope here would not be disposed and you can't(if you have default scope for your DbContext
) dispose the scope inside the Func
cause your context will be disposed also. So you can try creating some disposable wrapper so you can manually dispose everything like this:
public class DisposableScopedContextWrapper : IDisposable
{
private readonly IServiceScope _scope;
public DbContext Context { get; }
public DisposableScopedContextWrapper(IServiceScope scope)
{
_scope = scope;
Context = _scope.ServiceProvider.GetService<DbContext>();
}
public void Dispose()
{
_scope.Dispose();
}
}
services.AddSingleton<Func<DisposableScopedContextWrapper>>(provider =>() =>
{
var scope = provider.CreateScope();
return new DisposableScopedContextWrapper(scope);
});
Inject in your classes Func<DisposableScopedContextWrapper> func
and use it
using (var wrapper = func())
{
wrapper.Context...
}
来源:https://stackoverflow.com/questions/61601511/can-i-clone-dbcontext-from-existing-one