如何在Entity Framework Core 7.0.2中启用延迟加载及解决相关问题
问题背景
环境信息
- Windows 11 x64
- .NET 7.0.2、ASP.NET Core WebAPI 7.0.2
- Visual Studio 2022社区版
- Microsoft SQL Server 2014 Express版
已执行操作
已安装对应NuGet包:
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.2" />
DbContext配置:
public virtual DbSet<VoucherTypeCategory> VoucherTypeCategories { get; set; } public virtual DbSet<VoucherTypeCategoryRefType> VoucherTypeCategoryRefTypes { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseLazyLoadingProxies() .UseSqlServer("Server=.\\***********;Database=***********SampleVy;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true"); protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfiguration(new RoleConfiguration()); modelBuilder.Entity<Account>(entity => { entity.HasKey(e => new { e.AccountId, e.AccountNumber }); // 其他配置... }); }
问题现象
已配置.UseLazyLoadingProxies(),但延迟加载未生效(导航属性为空);最终目标是避免加载过多数据(原JSON达1.95MB),仅加载单表数据(仅几KB)。
后续尝试及报错
- 使用
.AsNoTracking()查询后,Postman报错:
{ "ErrorType": "Failure", "ErrorMessage": "An error was generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingWarning': An attempt was made to lazy-load navigation 'AccountDefaults' on a detached entity of type 'AccountProxy'. Lazy loading is not supported for detached entities or entities that are loaded with 'AsNoTracking'. This exception can be suppressed or logged by passing event ID 'CoreEventId.DetachedLazyLoadingWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'." }
- 全局设置
UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking),仍出现相同报错。
解决方案
一、正确启用延迟加载的前提条件
延迟加载生效需要满足以下所有条件:
- 导航属性必须标记为virtual:EF Core通过生成实体代理类,重写virtual导航属性来实现延迟加载。检查
Account类中所有需要延迟加载的导航属性(比如AccountDefaults)是否添加virtual关键字,示例:public class Account { // 主键字段... public virtual AccountDefaults AccountDefaults { get; set; } public virtual ICollection<OtherEntity> OtherNavigations { get; set; } } - 不能使用AsNoTracking/全局NoTracking:延迟加载依赖上下文对实体的跟踪,脱离上下文(detached)或无跟踪的实体无法触发延迟加载,这也是报错的核心原因。若要使用延迟加载,必须移除
AsNoTracking()和全局QueryTrackingBehavior.NoTracking配置。 - 确保DbContext的延迟加载配置生效:如果在
Program.cs的AddDbContext中配置上下文,需统一配置UseLazyLoadingProxies,避免和OnConfiguring冲突,示例:builder.Services.AddDbContext<Acc200Context>(options => options.UseSqlServer("你的连接字符串") .UseLazyLoadingProxies());
二、实现仅加载单表数据的方案
若核心需求是避免加载关联数据、减小JSON体积,推荐以下更直接的方法:
方法1:使用Select投影返回所需字段(推荐)
直接在查询中指定需要返回的列,返回匿名类型或自定义DTO,从根源上避免加载导航属性:
// 自定义DTO类,仅包含单表所需字段 public class AccountDto { public Guid AccountId { get; set; } public string AccountNumber { get; set; } // 其他需要的单表字段... } // 控制器中的查询逻辑 [HttpGet("{tenant_id}/all/")] [Authorize(Roles = "User")] public IEnumerable<AccountDto> Get(Guid tenant_id) { return _db.Accounts .Where(x => x.TenantId == tenant_id) .Select(x => new AccountDto { AccountId = x.AccountId, AccountNumber = x.AccountNumber // 映射其他需要的单表字段 }) .ToList(); }
方法2:关闭延迟加载,禁用导航属性序列化
如果不需要延迟加载,直接关闭它,并配置JSON序列化忽略导航属性:
- 移除
UseLazyLoadingProxies()配置; - 在JSON序列化配置中忽略未加载的导航属性(或直接标记
[JsonIgnore]在导航属性上):
或在实体类的导航属性上标记:// Program.cs中配置JSON序列化 builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; // 忽略null值的导航属性 options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; });[JsonIgnore] public AccountDefaults AccountDefaults { get; set; }
方法3:抑制延迟加载警告(不推荐,仅临时处理)
若必须使用AsNoTracking又不想看到报错,可以在DbContext配置中抑制该警告:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseLazyLoadingProxies() .UseSqlServer("你的连接字符串") .ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.DetachedLazyLoadingWarning));
此方法仅隐藏警告,未解决根本问题,导航属性依然无法加载,序列化时可能仍会出现空值或意外问题。
内容的提问来源于stack exchange,提问作者Đỗ Như Vỹ
相关产品推荐
相关产品推荐

