Can I clone DbContext from existing one?

烂漫一生 提交于 2021-02-05 11:59:24

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!