EF Core 7.0.7生成错误SQL:含不存在的PdfDocumentDocumentId列
解决EF Core生成SQL包含不存在列
PdfDocumentDocumentId的问题 问题场景
使用EF Core 7.0.7编写查询Template的代码后,生成的SQL中包含了Templates表不存在的[t].[PdfDocumentDocumentId]列,导致抛出SqlException: Invalid column name 'PdfDocumentDocumentId'异常。
查询代码
public async Task<Template?> GetTemplate(int templateId) { return await Context.Templates .Where(t => t.TemplateId == templateId) .FirstOrDefaultAsync(); }
生成的错误SQL
SELECT TOP(1) [t].[TemplateId], [t].[Active], [t].[AssociatedYear], [t].[Deleted], [t].[FinalSummaryScreenId], [t].[FirstScreenId], [t].[IntermediateSummaryScreenId], [t].[Name], [t].[NameResourceId], [t].[PdfDocumentDocumentId], [t].[TemplateTypeId], [r].[ResourceId] FROM [taxtool].[Templates] AS [t] LEFT JOIN [taxtool].[Resources] AS [r] ON [t].[NameResourceId] = [r].[ResourceId] WHERE [t].[TemplateId] = @__templateId_0 ORDER BY [t].[TemplateId], [r].[ResourceId]
相关实体与配置代码
Template实体
public class Template { public int TemplateId { get; set; } public int TemplateTypeId { get; set; } public int? FirstScreenId { get; set; } public int? IntermediateSummaryScreenId { get; set; } public int? FinalSummaryScreenId { get; set; } public required string Name { get; set; } public bool Active { get; set; } public int? NameResourceId { get; set; } public bool Deleted { get; set; } public int AssociatedYear { get; set; } public TemplateType? TemplateType { get; set; } public Screen? FirstScreen { get; set; } public Screen? IntermediateSummaryScreen { get; set; } public Screen? FinalSummaryScreen { get; set; } public Resource? NameResource { get; set; } }
Template实体配置
modelBuilder.Entity<Template>(entity => { entity.ToTable("Templates", "test"); entity.HasKey(e => e.TemplateId).HasName("PK_Templates"); entity.Property(e => e.Name) .IsRequired() .HasMaxLength(100); entity.HasOne(d => d.FinalSummaryScreen) .WithMany(p => p.FinalSummaryTemplates) .HasForeignKey(d => d.FinalSummaryScreenId) .HasConstraintName("FK_Templates_Screens_FinalSummaryScreen"); entity.HasOne(d => d.FirstScreen) .WithMany(p => p.FirstScreenTemplates) .HasForeignKey(d => d.FirstScreenId) .HasConstraintName("FK_Templates_Screens_FirstScreen"); entity.HasOne(d => d.IntermediateSummaryScreen) .WithMany(p => p.IntermediarySummeryTemplates) .HasForeignKey(d => d.IntermediateSummaryScreenId) .HasConstraintName("FK_Templates_Screens_IntermediateSummaryScreen"); entity.HasOne(d => d.NameResource) .WithMany(p => p.TemplateNames) .HasForeignKey(d => d.NameResourceId) .HasConstraintName("FK_Templates_Resources_Name"); entity.HasOne(d => d.TemplateType) .WithMany(p => p.Templates) .HasForeignKey(d => d.TemplateTypeId) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_Templates_TemplateType"); entity.Navigation(e => e.NameResource).AutoInclude(); });
多对多关系配置
modelBuilder.Entity<TemplatePdfDocumentMapping>(entity => { entity.ToTable("TemplatePDFMapping", "test"); entity.HasKey(e => new { e.TemplateId, e.PdfDocumentId }).HasName("PK_TemplatePDFMapping"); entity.Property(e => e.PdfDocumentId).HasColumnName("DocumentId"); entity.HasOne(d => d.Template) .WithMany(p => p.PdfDocumentMappings) .HasForeignKey(d => d.TemplateId) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_TemplatePDFMapping_Template"); entity.HasOne(d => d.PdfDocument) .WithMany(p => p.TemplateMappings) .HasForeignKey(d => d.PdfDocumentId) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_TemplatePDFMapping_Document"); }); modelBuilder.Entity<PdfDocument>(entity => { entity.ToTable("PDFDocument", "test"); entity.HasKey(e => e.DocumentId).HasName("PK_PDFDocument"); entity.Property(e => e.Label) .IsRequired() .HasMaxLength(160); entity.HasOne(d => d.Folder) .WithMany(p => p.PdfDocuments) .HasForeignKey(d => d.FolderId) .HasConstraintName("FK_PDFDocument_Folder"); });
问题原因
- EF Core的约定配置自动推断错误:配置中
.WithMany(p => p.PdfDocumentMappings)声明了Template与中间表的一对多关系,但EF Core错误尝试在Template实体上寻找指向PdfDocument的直接外键(按约定命名为PdfDocumentDocumentId),但实际该多对多关系仅通过中间表实现,无需Template表有直接外键列。 - 模型缓存过期:项目缓存中残留了旧的实体配置(比如曾存在过PdfDocument的直接导航属性),导致EF Core生成错误SQL。
解决方案
1. 补全Template实体的集合属性并显式配置关系
首先确保Template实体包含中间表的集合属性:
public class Template { // 其他属性... public ICollection<TemplatePdfDocumentMapping>? PdfDocumentMappings { get; set; } }
然后在Template实体配置中显式声明与中间表的关系,覆盖自动约定:
modelBuilder.Entity<Template>(entity => { // 其他配置... entity.HasMany(t => t.PdfDocumentMappings) .WithOne(m => m.Template) .HasForeignKey(m => m.TemplateId); });
2. 清理EF Core模型缓存
删除项目的bin和obj目录,重新生成解决方案;同时重启开发服务器,确保旧模型缓存被清空。
3. 检查并移除残留的导航属性
确认Template实体中没有未配置的PdfDocument直接导航属性(比如public PdfDocument? PdfDocument { get; set; }),如果有则直接删除。
内容的提问来源于stack exchange,提问作者pjominet
相关产品推荐
相关产品推荐

