EF Core延迟加载导航属性报错:未找到后备字段的问题排查
我了解后备字段(backing field)概念,有十年开发经验,但找不到以下代码中的问题:
public class Cal { public int ID { get; set; } public double? AreaSqFt { get; set; } public int? NumberOfPeople { get; set; } private ICollection<CalcOfSpaceContaminant> _сalcOfSpaceContaminants; public virtual ICollection<CalcOfSpaceContaminant> CalcOfSpaceContaminants { get => _сalcOfSpaceContaminants ??= new List<CalcOfSpaceContaminant>(); protected set => _сalcOfSpaceContaminants = value; } } public class CalcOfSpaceContaminant { public int ID { get; set; } public double? Vr { get; set; } public double? Cbz { get; set; } public double? Fr { get; set; } public int CalcID { get; set; } public virtual Cal Cal { get; set; } }
映射配置代码:
public class CalcOfSpaceContaminantMap : IEntityTypeConfiguration<CalcOfSpaceContaminant> { public void Configure(EntityTypeBuilder<CalcOfSpaceContaminant> builder) { builder.ToTable(nameof(CalcOfSpaceContaminant)); builder.HasKey(p => p.ID); builder.HasOne(contaminant => contaminant.Cal) .WithMany(cal => cal.CalcOfSpaceContaminants) .HasForeignKey(k => k.CalcID) .OnDelete(DeleteBehavior.Cascade); } }
执行配置代码:
builder.ApplyConfiguration(new CalcOfSpaceContaminantMap());
创建迁移时收到错误提示:
No backing field was found for property 'Cal.CalcOfSpaceContaminants'.
Lazy-loaded navigations must have backing fields. Either name the
backing field so that it is discovered by convention or configure the
backing field to use.
补充内容1
该问题并非ICollection导致,我在其他地方也用了相同写法且正常运行:
public partial class Zone { public int Id { get; set; } public string ZoneName { get; set; } private ICollection<Cal> _cals; public virtual ICollection<Cal> Cals { get => _cals ??= new List<Cal>(); protected set => _cals = value; } } public class CalMap : IEntityTypeConfiguration<Cal> { public void Configure(EntityTypeBuilder<Cal> builder) { builder.ToTable(nameof(Cal)); builder.HasKey(p => p.ID); builder.HasOne(p => p.Zone) .WithMany(z => z.Cals) .HasForeignKey(p => p.ZoneId) .OnDelete(DeleteBehavior.Cascade); } }
补充内容2
根据提示将后备字段名称中的西里尔字母'с'替换为拉丁字母's'后,第一个问题解决,但另一处无西里尔字母的代码仍报相同错误:
//public virtual ICollection<DownloadCenterFile> DownloadCenterFiles { get; protected set; } = new List<DownloadCenterFile>(); private ICollection<DownloadCenterFile> _files; public virtual ICollection<DownloadCenterFile> DownloadCenterFiles { get => _files ??= new List<DownloadCenterFile>(); protected set => _files = value; }
注释中的自动属性写法可正常运行,手动实现后备字段则报错。
问题根源与解决方案
1. 第一个问题:西里尔字母导致的命名不匹配
EF Core默认通过约定识别后备字段,要求字段名与属性名存在关联(如_<属性名>、m_<属性名>等格式)。你的第一个后备字段_сalcOfSpaceContaminants首字母是西里尔字母'с',而属性名是拉丁字母开头的CalcOfSpaceContaminants,EF Core无法识别两者的关联,因此报错。替换为拉丁字母's'后,命名符合约定,问题解决。
2. 第二个问题:后备字段命名约定不匹配
对于懒加载导航属性,EF Core的约定识别优先匹配与属性名前缀一致的后备字段。你当前的后备字段_files与属性名DownloadCenterFiles的名称关联度不足,EF Core无法自动识别。
解决方法:
- 方法一:显式配置后备字段
在实体的配置类中手动指定后备字段,让EF Core明确关联:
builder.Entity<YourEntity>() .Navigation(e => e.DownloadCenterFiles) .HasField("_files");
- 方法二:修改后备字段名以符合约定
将后备字段名改为与属性名对应的驼峰式前缀,让EF Core自动识别:
private ICollection<DownloadCenterFile> _downloadCenterFiles; public virtual ICollection<DownloadCenterFile> DownloadCenterFiles { get => _downloadCenterFiles ??= new List<DownloadCenterFile>(); protected set => _downloadCenterFiles = value; }
- 方法三:使用自动属性结合懒加载
如果不需要手动控制后备字段逻辑,直接使用注释中的自动属性写法,EF Core会自动处理后备字段:
public virtual ICollection<DownloadCenterFile> DownloadCenterFiles { get; protected set; } = new List<DownloadCenterFile>();
内容的提问来源于stack exchange,提问作者Oleg Sh

