【问题标题】:DBContext : Getting disposed without calling Dispose(). Not using a using statementDBContext :在不调用 Dispose() 的情况下进行处理。不使用 using 语句
【发布时间】:2020-03-06 22:32:28
【问题描述】:

我正在尝试对我的dbcontext 进行一些查询。我已将数据保存在数据库中,现在正尝试在线程中再次提取数据以进行进一步处理,但无法这样做。 dbcontext 以已处置的形式出现。

我尝试将dbcontext 的服务生命周期从默认范围修改为单例和瞬态,并将调用dbcontext 的类的生命周期更改为瞬态。

服务添加:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<PearlIDPContext>(options => options.UseMySQL(Configuration.GetConnectionString("IDPDatabase")), optionsLifetime: ServiceLifetime.Transient);
    services.AddScoped<IScanDataRepository, ScanDataRepository>();
    services.AddScoped<IOperationsRepository, OperationHistoryRepository>();
    services.AddScoped<IExtractedDataRepository, ExtractedDataRepository>();
    services.AddScoped<IExtractedColorsRepository, ExtractedColorsRepository>();
    services.AddScoped<IRejectionsRepository, RejectionsRepository>();
    services.AddScoped<IStartProcess, StartProcess>();
}

db修改类:

public class ScanDataRepository : IScanDataRepository
{
    private readonly PearlIDPContext context;

    public ScanDataRepository(PearlIDPContext context)
    {
        this.context = context;
    }
    public async Task<ScanData> AddAsync(ScanData scan) [modified]
    {
        context.ScanData.Add(scan);
        await context.SaveChangesAsync();
        return scan;
    }
    public ScanData GetScanData(string pearlId)
    {
       return context.ScanData.FirstOrDefault(o => o.PearlId == pearlId);
    }
}

调用修改类:

scanDataRepository.AddAsync(scanData);

try
{
    Logger.WriteToLogFile("Fetching Scan details from database for pearlID : " + pearlId, pearlId);

    scanData = scanDataRepository.GetScanData(pearlId); // this is line 39
    int id = scanData.ScanId;
    Logger.WriteToLogFile("Fetching Scan details from database successful for pearlID : " + pearlId + ". DB table id : " + id, pearlId);
}
catch (Exception ex)
{
    Logger.WriteToErrorFile("Error getting data from databse. Pearl ID : " + pearlId + ". Error : " + ex.ToString());
}

从数据库获取数据时出错。珍珠编号:PI09889。错误 : System.ObjectDisposedException:无法访问已处置的对象。一种 此错误的常见原因是处理已解决的上下文 从依赖注入,然后尝试使用相同的 应用程序中其他地方的上下文实例。如果您可能会发生这种情况 在上下文上调用 Dispose(),或者将上下文包装在 使用语句。如果你使用依赖注入,你应该让 依赖注入容器负责处理上下文 实例。对象名称:'PearlIDPContext'。在 Microsoft.EntityFrameworkCore.DbContext.CheckDisposed() 在 Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
在 Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Internal.IDbContextDependencies.get_StateManager() 在 Microsoft.EntityFrameworkCore.Query.QueryContextDependencies.get_StateManager() 在 Microsoft.EntityFrameworkCore.Query.QueryContext.get_StateManager() 在 Microsoft.EntityFrameworkCore.Query.QueryContext.BeginTrackingQuery() 在 Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 结果,QueryContext queryContext,IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext() 在 System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 源, 布尔值&发现)在 System.Linq.Enumerable.First[TSource](IEnumerable`1 源)在 Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.c__DisplayClass15_1`1.b__0(QueryContext 质量控制)在 Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](表达式 查询)在 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](表达式 表达式)在 System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 源, 表达式`1谓词)在 MyndIT.Models.ScanDataRepository.GetScanData(String PearlId) 在 D:\Projects\Github\PearlIDP\MyndIT\Models\ScanDataRepository.cs:line 33 在 MyndIT.StartProcess.ProcessStart(String PearlId) 中 D:\Projects\Github\PearlIDP\MyndIT\StartProcess.cs:39 行

【问题讨论】:

  • 不要将 Singleton 用于 db 上下文,它们是轻量级、短命的东西。使用适当的短寿命注入它们,不要试图以任何方式保留它们
  • 这是我尝试过的事情之一。我通常将其保留为 Scoped 并收到上述错误。
  • 在 Dispose 上设置一个断点,你会看到是谁在处理它
  • 我没有显式调用 Dispose 方法。你能指导我在哪里检查 dispose 方法吗?

标签: c# asp.net-core dependency-injection entity-framework-core


【解决方案1】:

您需要将 DbContext 保持为瞬态。我以前多次遇到过这个问题。发生的事情是该方法在线程完成之前完成并处理您的上下文。如果你使用线程来阻止 UI 锁定,那么你应该使用 await 关键字(实际上你应该使用 await)。

【讨论】:

  • 已将其视为瞬态。所有调用 dbcontext 的模型都有作用域。services.AddDbContext&lt;PearlIDPContext&gt;(options =&gt; options.UseMySQL(Configuration.GetConnectionString("IDPDatabase")), optionsLifetime: ServiceLifetime.Transient); services.AddScoped&lt;IScanDataRepository, ScanDataRepository&gt;(); services.AddScoped&lt;IOperationsRepository, OperationHistoryRepository&gt;(); services.AddScoped&lt;IExtractedDataRepository, ExtractedDataRepository&gt;();
【解决方案2】:

请确保找到此行的代码:

scanDataRepository.Add(scanData);

等待正常。如果此代码在返回 Task 的方法中执行,并且该任务未正确等待,则数据库最终可能会被释放,因为调用者已经完成,即使您的数据库操作仍处于挂起状态。

【讨论】:

  • 会这样做。有道理。
  • 已更改所有添加方法以添加 asysnc 和 await 无处不在。但是我仍然收到错误:
  • c# public async Task&lt;ScanData&gt; AddAsync(ScanData scan) { context.ScanData.Add(scan); await context.SaveChangesAsync(); return scan; } 已等待所有添加方法。问题仍然存在。用等待的方法更新了问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-15
  • 1970-01-01
  • 1970-01-01
  • 2012-08-07
相关资源
最近更新 更多