我可以从现有的 DbContext 克隆吗?

Can I clone DbContext from existing one?

我正在开发 .NET Core Web API,我有一个端点,我想在其中并行地 运行 三个操作。他们三个都使用同一个数据库,所以我需要 DbContext 的三个副本。我创建了一个简单的工厂 class,稍后我将其注入我的 "Data" class.

是否可以(如果可以,这是一个好习惯)将 DbContext 注入我的工厂 class(使用内置的 .NET Core IoC),当有人调用 "CreateMyDbContext" 方法时,只需深度克隆一开始注入的那个?

编辑: 以下是 DbContext 池的示例:

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();

        // ... 
    }
}

出于多种原因,我绝对不会推荐任何深度克隆,其中之一是您需要弄清楚很多 EF 内部结构才能使其正确,并且内部结构可能会发生变化(并且您需要花费一些时间在上面)。

第二种选择是手动创建上下文,我不建议这样做也会导致现代基础设施使用 DbContext 池化。

那么您可以像这样注册 Func<DbContext>(或创建您自己的工厂):

 services.AddSingleton<Func<DbContext>>(provider => () => 
        {
            var scope = provider.CreateScope();
            return scope.ServiceProvider.GetRequiredService<DbContext>();
        });    

这里的问题是这里的作用域不会被释放,你不能(如果你有你的 DbContext 的默认作用域)在 Func 中释放作用域,因为你的上下文将是处置也。所以你可以尝试创建一些一次性包装器,这样你就可以像这样手动处理所有东西:

    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);
        });

注入你的 类 Func<DisposableScopedContextWrapper> func 并使用它

 using (var wrapper = func())
        {
            wrapper.Context...
        }