EF Core异步调用ToListAsync遇数据库连接关闭错误求助
问题:异步执行IQueryable转List时出现数据库连接关闭错误
我从仓储层获取了三个IQueryable查询,在应用层用异步方式转换为List时,报错:
"BeginExecuteReader requires an open and available Connection. The connection's current state is closed."
由于性能要求必须用异步执行,需要解决这个问题。
应用层异步代码
private async Task<Tuple<List<GetCustomerDto>, List<GetSarfaslDto>, List<GetCusTellDto>>> getQuery() { try { var customersTask =await _customerRepository.GetCustomers().ToListAsync().ConfigureAwait(false); var sarfaslsTask = await _customerRepository.GetCustomerSarfasl().ToListAsync().ConfigureAwait(false); var cusTellsTask = await _cusTellRepository.GetCusTell().ToListAsync().ConfigureAwait(false); return new Tuple< List<GetCustomerDto>, List<GetSarfaslDto>, List<GetCusTellDto>>( customersTask, sarfaslsTask, cusTellsTask); } catch (Exception ex) { throw; } }
仓储层查询代码
public class CustomerRepository : ICustomerRepository { #region Feilds private readonly HolooDatabaseContext _context; #endregion public CustomerRepository(HolooDatabaseContext context) { _context = context; } public IQueryable<GetSarfaslDto> GetCustomerSarfasl() { var query = (from customer in _context.CUSTOMER join sarfasl in _context.SARFASL on customer.C_Code.Substring(RepositoryConstants.C_CODE) equals sarfasl.Sarfasl_Code.Substring(RepositoryConstants.SARFASL_C_CODE) where sarfasl.Col_Code.Equals(RepositoryConstants.SARFASL_CODE) select new GetSarfaslDto() { Sarfasl_Name = sarfasl.Sarfasl_Name, Common = sarfasl.Common, Col_Code = sarfasl.Col_Code, Moien_Code = sarfasl.Moien_Code, Tafzili_Code = sarfasl.Tafzili_Code, Sarfasl_Code = sarfasl.Sarfasl_Code, Group = sarfasl.Group, Mahiat = sarfasl.Mahiat, Can_Delete = sarfasl.Can_Delete, Parent = sarfasl.Parent, Type = sarfasl.Type, ArzId = sarfasl.ArzId, AutoUse = sarfasl.AutoUse, DefaultSarfasl_Code = sarfasl.DefaultSarfasl_Code, Delete = sarfasl.Delete, ID = sarfasl.ID, Mandeh = sarfasl.Mandeh, MHaz_Code = sarfasl.MHaz_Code, Money_Price = sarfasl.Money_Price, OldType = sarfasl.OldType, Sarfasl_Codeold = sarfasl.Sarfasl_Codeold, Selected = sarfasl.Selected, SParent = sarfasl.SParent, }).AsQueryable(); return query; } public IQueryable<GetCustomerDto> GetCustomers() { var query = (from customer in _context.CUSTOMER join bedBesView in _context.W0_Calc_BedBes_UseInView on customer.C_Code equals bedBesView.CCode into bdc from bd in bdc.DefaultIfEmpty() let ff = _context.FACTURE.DefaultIfEmpty() .FirstOrDefault(f => f.C_Code == customer.C_Code && f.Fac_Type == RepositoryConstants.FAC_TYPE_F) let fk = _context.FACTURE.DefaultIfEmpty() .FirstOrDefault(f => f.C_Code == customer.C_Code && f.Fac_Type == RepositoryConstants.FAC_TYPE_K) let vastehCount = _context.CustomerVaseteh.Count(c => c.C_Code == customer.C_Code) select new GetCustomerDto() { C_Code = customer.C_Code, C_Code_C = customer.C_Code_C, C_Name = customer.C_Name, Kharid = customer.Kharid, Forosh = customer.Forosh, Vaseteh = customer.Vaseteh, Vaseteh_Porsant = customer.Vaseteh_Porsant, Karshenas = customer.Karshenas, InListSiah = customer.InListSiah, SelectType = customer.SelectType, City_Code = customer.City_Code, First_BalanceSanad = customer.First_BalanceSanad, Sum_Takhfif = customer.Sum_Takhfif, Etebar = customer.Etebar, NetHlp = customer.NetHlp, Col_Code_Bed = customer.Col_Code_Bed, Moien_Code_Bed = customer.Moien_Code_Bed, ArzID = customer.ArzID, money_price = customer.money_price, CalledDate = customer.CalledDate, Creation_Date = customer.Creation_Date, National_Code = customer.National_Code, Economic_Code = customer.Economic_Code, C_Tel = customer.C_Tel, C_Mobile = customer.C_Mobile, C_Fax = customer.C_Fax, Cust_City = customer.Cust_City, Cust_Ostan = customer.Cust_Ostan, Cust_Mantagheh = customer.Cust_Mantagheh, Zip_Code = customer.Zip_Code, C_Address = customer.C_Address, Email_Address = customer.Email_Address, WebId = customer.WebId, C_type = customer.C_type, IsSeller = customer.IsSeller, Cust_type = customer.Cust_type, Agent = customer.Agent, Agent_Porsant = customer.Agent_Porsant, Anbardar = customer.Anbardar, Arayeshgar = customer.Arayeshgar, Arayesh_Porsant = customer.Arayesh_Porsant, Arz_Mandeh = customer.Arz_Mandeh, AwardCustomer = customer.AwardCustomer, Birth_Date = customer.Birth_Date, CAlarmEtebarCheck = customer.CAlarmEtebarCheck, Car_Id = customer.Car_Id, CheckReciveOfEtebar = customer.CheckReciveOfEtebar, Choice = customer.Choice, CityCodeLevy = customer.CityCodeLevy, Cobbler = customer.Cobbler, Col_Code_Bes = customer.Col_Code_Bes, Comment = customer.Comment, Companey_Code_F = customer.Companey_Code_F, CoName = customer.CoName, ContactDate = customer.ContactDate, Counective_Name = customer.Counective_Name, Counective_Tel = customer.Counective_Tel, Cust_Job = customer.Cust_Job, Cutter = customer.Cutter, C_AliasName = customer.C_AliasName, C_Code_C2 = customer.C_Code_C2, DarsadAmuzeshP = customer.DarsadAmuzeshP, DarsadEconomicCode = customer.DarsadEconomicCode, DarsadShahrdari = customer.DarsadShahrdari, Delete = customer.Delete, DressType = customer.DressType, Driver = customer.Driver, Endeditdate = customer.Endeditdate, Etebargerami = customer.Etebargerami, ExporterSId = customer.ExporterSId, FactOutOfEtebar = customer.FactOutOfEtebar, First_BalanceSanad_Bes = customer.First_BalanceSanad_Bes, Gender = customer.Gender, GroupId = customer.GroupId, HkharidarType1code = customer.HkharidarType1code, HlpAman = customer.HlpAman, Zone = customer.Zone, isAbkar = customer.isAbkar, isAbKonandeh = customer.isAbKonandeh, IsActive = customer.IsActive, isBonakdar = customer.isBonakdar, IsChange = customer.IsChange, IsCMS = customer.IsCMS, isFactory = customer.isFactory, isGoldmaker = customer.isGoldmaker, isHamkar = customer.isHamkar, iskifi = customer.iskifi, isMekhrajiKargah = customer.isMekhrajiKargah, isOtherCust = customer.isOtherCust, isReygir = customer.isReygir, isReygirKargah = customer.isReygirKargah, isShopper = customer.isShopper, isTamirKar = customer.isTamirKar, JavaherSaz = customer.JavaherSaz, KarPorsant = customer.KarPorsant, KarPorsantDarsad = customer.KarPorsant, KarPorsantType = customer.KarPorsantType, latitude = customer.latitude, longitude = customer.longitude, Mandehgold750 = customer.Mandehgold750, MandehPelatin = customer.MandehPelatin, Mekhrajkar = customer.Mekhrajkar, Mercer = customer.Mercer, ModifyDate = customer.ModifyDate, MohlatTasvieh = customer.MohlatTasvieh, Moien_Code_Bes = customer.Moien_Code_Bes, National_Code_F = customer.National_Code_F, Notionality = customer.Notionality, OstanCodeLevy = customer.OstanCodeLevy, PelakChar = customer.PelakChar, PelakCity = customer.PelakCity, Pelakcitycode = customer.Pelakcitycode, Pelakcode2 = customer.Pelakcode2, Pelakcode3 = customer.Pelakcode3, Personal_Code_F = customer.Personal_Code_F, Personel = customer.Personel, Porsant = customer.Porsant, Porsant2 = customer.Porsant2, PriceHamkar = customer.PriceHamkar, Res_cust = customer.Res_cust, SanadOutOfEtebar = customer.SanadOutOfEtebar, SarFasl_Amani_Dar = customer.SarFasl_Amani_Dar, SarFasl_Amani_Par = customer.SarFasl_Amani_Par, SenfId = customer.SenfId, SMSGroup = customer.SMSGroup, Tafzili_Code_Bed = customer.Tafzili_Code_Bed, Tafzili_Code_Bes = customer.Tafzili_Code_Bes, Tailor = customer.Tailor, TasviehType = customer.TasviehType, TimeEndCustArayesh = customer.TimeEndCustArayesh, TimeStartCustArayesh = customer.TimeStartCustArayesh, UserCodeCust = customer.UserCodeCust, Vaseteh_Code = customer.Vaseteh_Code, Vaseteh_Porsant_C = customer.Vaseteh_Porsant_C, }).AsQueryable(); return query; } }
解决方案
1. 并行执行异步任务,避免连接被释放
当前代码串行await每个任务,前一个任务执行完后DbContext可能释放连接,导致后续任务出错。应先启动所有异步任务,再统一等待完成:
private async Task<Tuple<List<GetCustomerDto>, List<GetSarfaslDto>, List<GetCusTellDto>>> getQuery() { try { // 先启动所有异步任务,不立即await var customersTask = _customerRepository.GetCustomers().ToListAsync().ConfigureAwait(false); var sarfaslsTask = _customerRepository.GetCustomerSarfasl().ToListAsync().ConfigureAwait(false); var cusTellsTask = _cusTellRepository.GetCusTell().ToListAsync().ConfigureAwait(false); // 等待所有任务完成 await Task.WhenAll(customersTask, sarfaslsTask, cusTellsTask).ConfigureAwait(false); return new Tuple< List<GetCustomerDto>, List<GetSarfaslDto>, List<GetCusTellDto>>(await customersTask, await sarfaslsTask, await cusTellsTask); } catch (Exception ex) { throw; } }
2. 确保DbContext生命周期正确
如果DbContext是请求范围(如ASP.NET Core默认Scoped),需保证异步任务执行期间DbContext未被提前释放。检查依赖注入配置,确保仓储和DbContext生命周期匹配(均设为Scoped)。
3. 优化仓储层查询,避免N+1问题
GetCustomers中的FirstOrDefault会触发N+1查询,加剧连接压力。可改为左连接或投影子查询,合并逻辑到主查询:
// 优化FirstOrDefault逻辑,改为单次查询内的子查询 let ff = (from f in _context.FACTURE where f.C_Code == customer.C_Code && f.Fac_Type == RepositoryConstants.FAC_TYPE_F select f).FirstOrDefault()
4. 显式管理连接(备选方案)
若以上方法无效,可在执行查询前显式打开连接,完成后关闭:
private async Task<Tuple<List<GetCustomerDto>, List<GetSarfaslDto>, List<GetCusTellDto>>> getQuery() { try { await _context.Database.OpenConnectionAsync().ConfigureAwait(false); var customersTask = await _customerRepository.GetCustomers().ToListAsync().ConfigureAwait(false); var sarfaslsTask = await _customerRepository.GetCustomerSarfasl().ToListAsync().ConfigureAwait(false); var cusTellsTask = await _cusTellRepository.GetCusTell().ToListAsync().ConfigureAwait(false); _context.Database.CloseConnection(); return new Tuple< List<GetCustomerDto>, List<GetSarfaslDto>, List<GetCusTellDto>>(customersTask, sarfaslsTask, cusTellsTask); } catch (Exception ex) { _context.Database.CloseConnection(); throw; } }
注意:此方法需确保连接正确关闭,避免泄漏,优先推荐前三种方案。
内容的提问来源于stack exchange,提问作者shirin monzavi
相关产品推荐
相关产品推荐

