У меня есть пакетное задание, которое анализирует файл 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();
}
Есть мысли о том, почему я все еще получаю эту ошибку?
Обновлено с помощью кода.
Чтобы убедиться, что я получаю новый экземпляр своего 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 различных таблиц.
Пожалуйста, публикуйте код, а не скриншоты