EF Core懒加载时DbContext释放后无法访问导航属性的解决方案
问题场景
现有基于Entity Framework Core的ASP.NET应用,定义了如下两个实体模型:
客户模型:
public class CustomerModel { public int Id{get;set; } [Required] public string Name {get;set; } [Required] public string Surname { get; set; } [Required] [Range(18,110)] public uint Age { get; set; } [Required] public virtual AdressModel Adress { get; set; } [Required] public DateTime Created { get; set; } }
地址模型:
public class AdressModel { public int Id { get; set; } [Required] public int HouseNumber { get; set; } [Required] public string Town { get; set; } [Required] public string ZipCode { get; set; } [Required] public string Country { get; set; } }
项目使用的DbContext定义如下:
public class DemoContext : DbContext { public DbSet<CustomerModel> Customers { get; set; } public DbSet<AdressModel> Adresses { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder options) { options.UseLazyLoadingProxies(); options.UseSqlite(@"Data Source=/home/ask/RiderProjects/Parkz/identifier.sqlite"); } }
控制器中sendhere接口尝试加载所有客户及关联的地址数据,实现代码:
public IActionResult sendhere() { List<CustomerModel> customers = new List<CustomerModel>(); using (var db = new DemoContext()) { customers = db.Customers .Include(c => c.Adress) .ToList(); } return Content("hi"); }
调试时发现退出using代码块后,访问关联的地址对象会抛出以下异常:
System.InvalidOperationException: An error was generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.LazyLoadOnDisposedContextWarning': An attempt was made to lazy-load navigation 'CustomerModelProxy.Adress' after the associated DbContext was disposed. This exception can be suppressed or logged by passing event ID 'CoreEventId.LazyLoadOnDisposedContextWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'. at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition`2.Log[TLoggerCategory](IDiagnosticsLogger`1 logger, TParam1 arg1, TParam2 arg2) at Microsoft.EntityFrameworkCore.Diagnostics.CoreLoggerExtensions.LazyLoadOnDisposedContextWarning(IDiagnosticsLogger`1 diagnostics, DbContext context, Object entityType, String navigationName) at Microsoft.EntityFrameworkCore.Infrastructure.Internal.LazyLoader.ShouldLoad(Object entity, String navigationName, NavigationEntry& navigationEntry) at Microsoft.EntityFrameworkCore.Infrastruc…
已确认异常触发时机为using块执行完毕、DbContext被释放后,需要实现DbContext释放后仍可正常访问客户关联地址数据、供视图返回使用。
问题根因
配置中开启了懒加载代理(UseLazyLoadingProxies()),EF Core会为实体生成继承自原实体的代理子类。即使已经通过Include预加载了关联地址数据,访问导航属性时代理类仍会优先执行懒加载检查逻辑,验证关联DbContext是否可用。此时DbContext已经被释放,检查逻辑直接抛出异常,和预加载是否成功没有关系。
解决方案
任选一种即可,优先推荐第一种:
- 方案1:查询时增加
AsNoTracking关闭变更跟踪。关闭跟踪后EF Core不会生成带懒加载逻辑的代理对象,直接返回导航属性已填充完成的普通实体实例,上下文释放后访问属性不会触发懒加载检查。
修改后的查询代码:
using (var db = new DemoContext()) { customers = db.Customers .Include(c => c.Adress) .AsNoTracking() .ToList(); }
- 方案2:全局关闭懒加载代理。如果项目中所有关联数据都通过
Include显式预加载,直接删除OnConfiguring方法里的options.UseLazyLoadingProxies();即可,EF不会再生成代理类,从根源上避免这类问题。 - 方案3:保留全局懒加载能力,仅当前查询禁用代理。使用
AsNoTrackingWithIdentityResolution替代AsNoTracking,既可以关闭代理生成,还能保留对象标识解析,避免同一实体被重复创建实例:
using (var db = new DemoContext()) { customers = db.Customers .Include(c => c.Adress) .AsNoTrackingWithIdentityResolution() .ToList(); }
注意:不要按照异常提示去抑制
LazyLoadOnDisposedContextWarning警告,这种做法只是掩盖错误,后续如果有未预加载的导航属性被访问,会直接返回null而不抛出明确异常,极易引发难排查的空引用问题。
内容的提问来源于stack exchange,提问作者Grazosi
相关产品推荐
相关产品推荐

