【问题标题】:Autofac - Retrieving new instance of UnitOfWork - "DBcontext has been disposed error"Autofac - 检索 UnitOfWork 的新实例 - “DBcontext 已被处理错误”
【发布时间】:2018-12-17 13:45:06
【问题描述】:

我有一个批处理作业,它正在解析 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();
    }

关于为什么我仍然收到此错误的任何想法?

【问题讨论】:

  • 请贴代码而不是截图
  • 已更新代码。

标签: c# entity-framework entity-framework-6 autofac


【解决方案1】:

为确保在每批操作后获得 UnitOfWork 的新实例,我检索对当前 Autofac 生命周期范围的引用,并要求 Autofac 在 using 语句中给我一个新的生命周期范围,然后我使用 Autofac 注册并解决这些依赖关系。我的一些服务也依赖于 UnitOfWork,因此获得这些依赖项的新实例也很重要。

这是一个精简的 sn-p:

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 个不同的表中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-19
    • 2017-08-22
    • 2016-05-27
    • 2015-08-17
    • 1970-01-01
    • 2013-04-20
    • 2021-08-31
    • 1970-01-01
    相关资源
    最近更新 更多