You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# EF查询方法转异步实现报错及性能优化求助

问题根因

你当前代码执行慢、异步方法报错的核心原因有两个:

  1. 你在过滤条件前加了AsEnumerable(),这会让EF直接把AP_SUPPLIER_2307整张表的数据全部加载到应用内存中,后续的Where过滤是在内存里遍历全表做的,表数据量越大执行越慢。同时AsEnumerable()返回的是内存集合类型IEnumerable<T>,EF提供的FirstOrDefaultAsync、ToListAsync等异步扩展方法是针对数据库查询类型IQueryable<T>的,自然会报找不到方法的错误。
  2. 你在Select映射逻辑里反复调用GetUploadFileDetails(x.UL_ID)、GetTaxCode(),每遍历一条主表记录就会发起一次单独的数据库查询,也就是典型的N+1查询问题,记录越多额外查询次数越多,性能会指数级下降。

注意:异步查询本身不会缩短查询执行的时间,它的作用是在等待数据库返回结果时释放应用线程,避免阻塞请求。你遇到的性能问题本质是查询写法不合理导致的,和同步/异步没有直接关系。

修复方案

按以下步骤调整代码即可解决性能问题,同时正确实现异步查询:

  • 移除过滤前的AsEnumerable()调用,让Where条件被EF翻译成SQL语句,在数据库端完成过滤,只拉取符合headerID条件的目标数据,避免全表加载。
  • 提前收集主表记录关联的所有外键ID,批量查询关联的上传文件、税码数据,不要在遍历映射时单条查库,解决N+1问题。
  • 用EF提供的ToListAsync()等异步方法执行实际的数据库IO操作,不要对内存集合调用异步扩展方法。
  • 给AP_SUPPLIER_2307表的AP_2307_HDR_ID字段加数据库索引,能进一步大幅提升过滤速度。

修正后的代码参考:

public async Task<IEnumerable<E2307DetailsViewModel>> GetE2307Details(long headerID)
{
    // 数据库端执行过滤,只拉取目标header对应的数据
    var supplierRecords = await entities.AP_SUPPLIER_2307
        .Where(x => x.AP_2307_HDR_ID == headerID)
        .ToListAsync();

    if (!supplierRecords.Any())
    {
        return Enumerable.Empty<E2307DetailsViewModel>();
    }

    // 批量查询所有关联数据,避免N+1查询
    var relatedUlIds = supplierRecords.Select(x => x.UL_ID).Distinct().ToList();
    // 这里需要实现按ID批量查上传文件的方法,替代原来的单条查询
    var uploadFileMap = (await GetUploadFileDetailsBatchByIds(relatedUlIds))
        .ToDictionary(x => x.UL_ID, x => x);
    var taxCodeMap = (await GetTaxCodeAsync())
        .ToDictionary(x => x.ATCCode, x => x.NatureOfPayment);

    // 内存中映射视图模型,无额外数据库开销
    return supplierRecords.Select(x =>
    {
        uploadFileMap.TryGetValue(x.UL_ID, out var uploadFile);
        taxCodeMap.TryGetValue(x.ATCCode, out var natureOfPayment);
        var taxRate = x.TAX_RATE / 100;
        return new E2307DetailsViewModel
        {
            APSupplier2307ID = x.AP_SUPPLIER_2307_ID,
            AP2307HeaderID = x.AP_2307_HDR_ID,
            UploadFileID = x.UL_ID,
            TransactionAPJEID = x.TRANS_APJE_ID,
            TransactionDescription = x.TRANS_DESCRIPTION,
            TransactionDate = x.TRANS_DATE,
            ReferenceNo = x.REFERENCE_NO,
            InvoiceNo = x.INVOICE_NO,
            ATCCode = x.ATC_CODE,
            TaxRate = x.TAX_RATE,
            AmtOfTaxWithHeld = x.AMOUNT_OF_TAX_WITHHELD,
            ForTheMonthOf = uploadFile?.FOR_THE_MONTH_OF,
            IncomePayment = taxRate == 0 ? 0 : x.AMOUNT_OF_TAX_WITHHELD / taxRate,
            MonthNo = uploadFile?.FOR_THE_MONTH_OF_NO ?? 0,
            NatureOfPayment = natureOfPayment,
            ForTheYearOf = uploadFile?.FOR_THE_YEAR
        };
    });
}

内容的提问来源于stack exchange,提问作者Cedric VH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 08:00:36