我有一个批处理作业,它正在解析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时,它因错误而掉落:
该操作无法完成,因为DbContext已被执行 处置。
我的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();
}
关于为什么我仍然遇到此错误的任何想法?
答案 0 :(得分:0)
为确保每一批操作后都能获得新的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个不同的表中。