EF Core 6未使用指定外键却生成Shadow Key报错求助
EF Core 6.0.9 数据库优先模式下贪婪加载关联表时生成不存在的影子键问题
使用EF Core 6.0.9通过数据库优先模式生成模型,在贪婪加载关联表时无法加载BeschaeftigungsAddendum表,报错提示:Invalid column name 'BeschaeftigungBid'。该字段既未在代码中定义,数据库中也不存在,推测EF Core在此处自动生成了影子键。已按照文档配置正确外键,但问题依旧。
实体配置代码
BeschaeftigungsAddendum 配置
modelBuilder.Entity<BeschaeftigungsAddendum>(entity => { entity.HasKey(e => e.Baid); entity.HasIndex(e => new { e.Beschaeftigung, e.Addendum }, "IX_BeschaeftigungsAddendum") .IsUnique(); entity.Property(e => e.Baid).HasColumnName("BAID"); entity.Property(e => e.Addendum) .IsRequired() .HasMaxLength(64) .IsUnicode(false); entity.Property(e => e.Expires) .HasColumnType("datetime") .HasDefaultValueSql("('9999-12-31T23:59:59')"); entity.Property(e => e.LastUpdate) .IsRequired() .HasMaxLength(20) .IsUnicode(false) .IsFixedLength(); entity.Property(e => e.Lastversion) .IsRequired() .IsRowVersion() .IsConcurrencyToken() .HasColumnName("lastversion"); entity.Property(e => e.Wert) .IsRequired() .HasMaxLength(256); entity.HasOne(d => d.BeschaeftigungNavigation) .WithMany(p => p.BeschaeftigungsAddendum) .HasForeignKey(d => d.Beschaeftigung) .HasConstraintName("FK_BeschaeftigungsAddendum_Beschaeftigung"); });
Beschaeftigung 配置
modelBuilder.Entity<Beschaeftigung>(entity => { entity.HasKey(e => e.Bid); entity.HasComment("Nachweis der Beschaeftigungsverhaeltnisse"); entity.HasIndex(e => new { e.Mitarbeiter, e.Beginn, e.KostenStelle, e.DatenQuelle }, "IX_Beschaeftigung") .IsUnique(); entity.Property(e => e.Bid) .HasColumnName("BID") .HasComment("Schluessel"); entity.Property(e => e.Beginn) .HasColumnType("datetime") .HasComment("Beschaeftigungsbeginn (W3CDTF)"); entity.Property(e => e.DienstBezeichnung).HasComment("Verweis nach Dienstbezeichnung"); entity.Property(e => e.Einrichtung).HasComment("Verweis nach Diensstelle"); entity.Property(e => e.Ende) .HasColumnType("datetime") .HasComment("Beschaeftigugsende (W3CDTF)"); entity.Property(e => e.Expires) .HasColumnType("datetime") .HasDefaultValueSql("('9999-12-31T23:59:59')"); entity.Property(e => e.KostenStelle) .IsRequired() .HasMaxLength(10) .IsUnicode(false) .HasComment("Verweis nach Diensstelle"); entity.Property(e => e.LastUpdate) .IsRequired() .HasMaxLength(20) .IsUnicode(false) .IsFixedLength() .HasComment("Zeitstempel (W3CDTF)") .UseCollation("Latin1_General_CI_AS"); entity.Property(e => e.Lastversion) .IsRequired() .IsRowVersion() .IsConcurrencyToken() .HasColumnName("lastversion") .HasComment("wegen Concurrency"); entity.Property(e => e.Updater).HasComment("Verweis nach Person"); entity.Property(e => e.Wd).HasColumnName("WD"); entity.HasOne(d => d.DatenQuelleNavigation) .WithMany(p => p.Beschaeftigung) .HasForeignKey(d => d.DatenQuelle) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_Beschaeftigung_DatenQuelle"); entity.HasOne(d => d.DienstBezeichnungNavigation) .WithMany(p => p.Beschaeftigung) .HasForeignKey(d => d.DienstBezeichnung) .OnDelete(DeleteBehavior.Cascade) .HasConstraintName("FK_Beschaeftigung_Dienstbezeichnung"); entity.HasOne(d => d.EinrichtungNavigation) .WithMany(p => p.Beschaeftigung) .HasForeignKey(d => d.Einrichtung) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_Beschaeftigung_Einrichtung"); entity.HasOne(d => d.MitarbeiterNavigation) .WithMany(p => p.Beschaeftigung) .HasForeignKey(d => d.Mitarbeiter) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_Beschaeftigung_Mitarbeiter"); });
模型类代码
Beschaeftigung 类
public partial class Beschaeftigung { public Beschaeftigung() { BeschaeftigungsAddendum = new HashSet<BeschaeftigungsAddendum>(); BueroAnschrift = new HashSet<BueroAnschrift>(); } /// <summary> /// Schluessel /// </summary> public int Bid { get; set; } public int Mitarbeiter { get; set; } /// <summary> /// Beschaeftigungsbeginn (W3CDTF) /// </summary> public DateTime Beginn { get; set; } /// <summary> /// Beschaeftigugsende (W3CDTF) /// </summary> public DateTime Ende { get; set; } public bool Wd { get; set; } /// <summary> /// Verweis nach Dienstbezeichnung /// </summary> public int? DienstBezeichnung { get; set; } /// <summary> /// Verweis nach Diensstelle /// </summary> public int Einrichtung { get; set; } /// <summary> /// Verweis nach Diensstelle /// </summary> public string KostenStelle { get; set; } public DateTime Expires { get; set; } /// <summary> /// Verweis nach Person /// </summary> public int Updater { get; set; } /// <summary> /// Zeitstempel (W3CDTF) /// </summary> public string LastUpdate { get; set; } /// <summary> /// wegen Concurrency /// </summary> public byte[] Lastversion { get; set; } public int DatenQuelle { get; set; } public virtual DatenQuelle DatenQuelleNavigation { get; set; } public virtual Dienstbezeichnung DienstBezeichnungNavigation { get; set; } public virtual Einrichtung EinrichtungNavigation { get; set; } public virtual Mitarbeiter MitarbeiterNavigation { get; set; } public virtual ICollection<BeschaeftigungsAddendum> BeschaeftigungsAddendum { get; set; } public virtual ICollection<BueroAnschrift> BueroAnschrift { get; set; } }
BeschaeftigungsAddendum 类
public partial class BeschaeftigungsAddendum { public int Baid { get; set; } public int Beschaeftigung { get; set; } public string Addendum { get; set; } public string Wert { get; set; } public DateTime Expires { get; set; } public int Updater { get; set; } public string LastUpdate { get; set; } public byte[] Lastversion { get; set; } public virtual Beschaeftigung BeschaeftigungNavigation { get; set; } }
查询代码
using (var kommDBContext = new kommdbContext(kommDBConnection)) { queryContext = kommDBContext.Person; queryContext = queryContext .Include(p => p.Mitarbeiter) .ThenInclude(m => m.Beschaeftigung) .ThenInclude(b => b.BeschaeftigungsAddendum); var sql = queryContext.ToQueryString(); result = queryContext.ToList(); }
已尝试过重命名BeschaeftigungsAddendum.Beschaeftigung字段、显式添加外键属性、添加未映射的BeschaeftigungBid字段等方法,但EF Core仍生成不存在的影子键,生成的SQL中包含未定义的[b0].[BeschaeftigungBid]列。
排查与解决步骤
- 显式指定关联主键:修改
BeschaeftigungsAddendum的实体配置,明确指定主实体的主键,避免EF Core自动推断错误:
entity.HasOne(d => d.BeschaeftigungNavigation) .WithMany(p => p.BeschaeftigungsAddendum) .HasForeignKey(d => d.Beschaeftigung) .HasPrincipalKey(p => p.Bid) // 显式关联主实体主键 .HasConstraintName("FK_BeschaeftigungsAddendum_Beschaeftigung");
- 检查命名约定冲突:EF Core默认约定会根据导航属性名称推断外键,若导航属性名称与外键字段名称不匹配,可能触发错误推断。可以尝试将
BeschaeftigungsAddendum中的Beschaeftigung字段重命名为BeschaeftigungBid,同时同步数据库字段(若允许),或保持字段名称并通过配置强制绑定。 - 重新生成模型:使用数据库优先的脚手架命令重新生成模型,确保配置与数据库结构完全一致:
Scaffold-DbContext "你的数据库连接字符串" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Force
- 清理上下文缓存:检查
DbContext中是否存在重复的关联配置,确保仅在一处定义Beschaeftigung与BeschaeftigungsAddendum的关系,避免冲突。
内容的提问来源于stack exchange,提问作者CaptainPirate
相关产品推荐
相关产品推荐

