EFCore 2.0:在上一个操作完成之前,第二个操作在此上下文中启动

EFCore 2.0 : A second operation started on this context before a previous operation completed

我明白错误的意思,但无法实施解决方案。我需要在线程中调用的方法中调用数据库(仅 select)。

我为此搜索了多个答案并尝试添加 ServiceLifetime.Transient 但得到了相同的结果。看起来我的 DI 有问题。

我也试过将构造函数中的 Context 传递给 PriceSheetAsyncRepository 但没有成功。

public class PriceSheetRepository : IPriceSheetRepository
{
    private readonly Pricing_PortalContext _context;
    private readonly ILogger _logger;

    public PriceSheetRepository(Pricing_PortalContext context, ILogger<PriceSheetRepository> logger)
    {
        _context = context;
        _logger = logger;
    }
    public async Task<bool> ProcessPriceSheetImport(long ImportId)
    {
        var pricesheetAsyncRepo = new PriceSheetAsyncRepository(_logger);

        foreach (var i in RequestList)
        {
            tasks.Add(Task.Run(async () => await pricesheetAsyncRepo.ValidatePublishAsync(i, _context)));
        }
        await Task.WhenAll(tasks);
    }
}


public class PriceSheetAsyncRepository
{
    private readonly ILogger _logger;

    public PriceSheetAsyncRepository(ILogger logger)
    {
        _logger = logger;

    }

    public Task<bool> ValidatePublishAsync(PriceSheetImportModel i, MyDBContext _context)
    {
        return Task.Run(() =>
        {
            i.IsValid = true;
            i.LinePart = i.LinePart?.ToUpper();

            if (effDate != null && _context.MyTablePublish.Where(x => x.A == i.A).Any())
            {
                i.IsValid = false;
                i.Message = i.Message + "Duplicate published record, ";
            }
        }

     }
}

任何人都可以指出我在这里做错了什么吗?

简而言之 - Entity Frameworks 上下文不是线程安全的,不允许多个操作并行 运行。

如果您实际上有不同的上下文实例,Transient 就可以工作。但在您的情况下,您只是在多个并发任务上使用上下文。

要么使您的代码成为单线程代码(for 循环在内部等待,而不是添加到任务列表并使用 Task.WhenAll),要么为您要使用它的每个任务创建一个新的上下文实例。

后者的示例可能如下所示(注意删除 Task.Run - 它伤害了你,没有帮助)

// in container builder
services.AddTransient<Pricing_PortalContext>();
services.AddTransient<Func<Pricing_PortalContext>>(sp => sp.GetRequiredService<Pricing_PortalContext>());

// inject a Func
public PriceSheetRepository(Func<Pricing_PortalContext> contextFactory, ILogger<PriceSheetRepository> logger)

// create a new func per task
tasks.Add(async () => await pricesheetAsyncRepo.ValidatePublishAsync(i, _contextFactory()));

虽然你的问题有正确答案,但看起来你正试图用锤子杀死苍蝇。为你的问题召集一堆任务是多余的。

public async Task ProcessPriceSheetImport(long ImportId)
{
    var ids = RequestList.Select(x => x.A);

    var existent = new HasSet<int>(await context.MyTablePublish.Where(x => ids.Contains(x.A)).Select(x => x.A).ToList());

    foreach (var i in RequestList)
    {
        if (existent.Contains(i.A))
        {
            i.IsValid = false;
            i.Message = i.Message + "Duplicate published record, ";
        }
    }
}