Могу ли я клонировать DbContext из существующего? - PullRequest
0 голосов
/ 04 мая 2020

Я работаю. NET Core Web API, и у меня есть одна конечная точка, на которой я хочу выполнять три операции параллельно. Все трое используют одну и ту же базу данных, поэтому мне нужно три копии DbContext. Я создал простой класс Factory, который позже вставил в свой класс Data.

Возможно ли (если это хорошая практика) внедрить DbContext в мой класс factory (используя встроенный. NET Core Io C) и когда кто-то вызывает метод CreateMyDbContext, просто глубоко клонируйте тот, который был введен в начале?

EDIT: Вот пример с 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();

        // ... 
    }
}

1 Ответ

2 голосов
/ 05 мая 2020

Я определенно не рекомендую глубокое клонирование по нескольким причинам, одна из которых заключается в том, что вам нужно будет выяснить множество внутренних компонентов 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...
        }
...