Autofac - Получение нового экземпляра UnitOfWork - «Ошибка удаления DBcontext»

У меня есть пакетное задание, которое анализирует файл CSV, а также создает и обрабатывает записи. В каждой строке я должен выполнять коммиты, поскольку мне нужно создавать сущности, а затем использовать результаты созданных сущностей.

Поскольку существует тысячи записей, производительность низкая, и я пытаюсь улучшить свою производительность.

У меня есть код, который выглядит примерно так:

var data = ParseExcel(filePath);
Setup();

foreach (var batch in data.Split(20))
{
    foreach (var row in batch)
    {
        try
        {
            ParseRow(row);
        }
        catch (Exception e)
        {
            JobLogger.Error(e, "Failed to parse row. Exception: " + e.Message);
            throw;
        }
    }

    _unitOfWork.Commit();
    _unitOfWork.Dispose();
    _unitOfWork = LifetimeScope.Resolve<Owned<IUnitOfWork>>().Value;
    ClientRepository = LifetimeScope.Resolve<Owned<IEntityBaseRepository<Client>>>().Value;

Мой метод Dispose выглядит так:

public void Dispose()
{
    _dbContext.Dispose();
    _dbContext = null;
    _dbFactory.Dispose();
    _dbFactory = null;
    GC.SuppressFinalize(this);
}

Намерение здесь состоит в том, что после обработки каждого пакета записей я хочу обновить единицу работы, удалив ее и запросив, чтобы Autofac сгенерировал ее новый экземпляр.

Однако в тот момент, когда я добавляю элемент в свой ClientRepository, он вылетает с ошибкой:

The operation cannot be completed because the DbContext has been disposed.

My ClientRepository использует общий класс репозитория, который выглядит следующим образом:

public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IEntityBase, new()
    {
        private DataContext _dataContext;

        #region Properties
        protected IDbFactory DbFactory
        {
            get;
        }

        protected DataContext DbContext => _dataContext ?? (_dataContext = DbFactory.Initialise());

        public EntityBaseRepository(IDbFactory dbFactory)
        {
            DbFactory = dbFactory;
        }

        #endregion

Вот часть моего UnitOfWork:

public class UnitOfWork : IUnitOfWork, IDisposable
{
    private IDbFactory _dbFactory;
    private DataContext _dbContext;

    public UnitOfWork(IDbFactory dbFactory)
    {
        _dbFactory = dbFactory;
    }

    public DataContext DbContext => _dbContext ?? (_dbContext = _dbFactory.Initialise());

    public void Commit()
    {
        DbContext.Commit();
    }

Есть мысли о том, почему я все еще получаю эту ошибку?

Пожалуйста, публикуйте код, а не скриншоты

Tobias Moe Thorstensen 17.12.2018 14:48

Обновлено с помощью кода.

Ciaran Gallagher 17.12.2018 16:19
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
260
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы убедиться, что я получаю новый экземпляр своего UnitOfWork после каждого пакета операций, я получаю ссылку на текущую область действия Autofac и прошу Autofac предоставить мне новую область действия внутри оператора using, затем я использую Autofac для регистрации и разрешения этих проблем. зависимости. Некоторые из моих сервисов также зависят от UnitOfWork, поэтому было важно, чтобы я также получил свежие экземпляры этих зависимостей.

Вот сокращенный фрагмент:

foreach (var batch in data.Split(10))
{
    using (var scope = LifetimeScope.BeginLifetimeScope("UnitOfWork", b =>
    {
        b.RegisterType<UnitOfWork>().AsImplementedInterfaces().InstancePerLifetimeScope();
        b.RegisterType<MyService>().AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();
        b.RegisterGeneric(typeof(EntityBaseRepository<>)).As(typeof(IEntityBaseRepository<>)).InstancePerLifetimeScope();
    }))
    {
        UnitOfWork = scope.Resolve<IUnitOfWork>();
        MyService = scope.Resolve<IMyService>();

        foreach (var row in batch)
        {
            try
            {
                ParseRow(row);
            }
            catch (Exception e)
            {
                JobLogger.Error(e, "Failed to parse row. Exception: " + e.Message);
                throw;
            }

        }
    }
}

В приведенном выше коде я дал имя «UnitOfWork» вложенной области времени существования.

Благодаря этому коду производительность задания значительно улучшилась, поскольку на этот раз я не использовал повторно один и тот же экземпляр UnitOfWork, который отслеживал десятки тысяч изменений при обработке файла.

Кроме того, я перестал разбивать данные на пакеты по 10 штук - вместо этого я решил получить новый UnitOfWork после обработки каждой строки, поскольку каждая строка уже включала вставку данных как минимум в 10 различных таблиц.

Другие вопросы по теме