You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改EF Core生成的关联列默认名称,解决查询报错问题

问题

执行以下代码(泛型<TDbEntity>实际为VgnItmDbEntity):

var entity = await context.Set<TDbEntity>().Include(e => e.VgnItmImages)
    .ThenInclude(vi => vi.Image)
    .FirstOrDefaultAsync(v => v.Id == id);

出现Npgsql.PostgresException报错,提示'42703: column v0.VgnItmDbEntityId does not exist'。

实际数据库中外键列名为VgnItmId,但EF Core运行时仍在查找默认生成的VgnItmDbEntityId列,已手动修改迁移删除旧列,但问题依旧,使用EF Core 8.0.4。

实体类及OnModelCreating配置代码如下:

public class VgnItmDbEntity : CreatedBySomeoneDbEntity
{
    [Required]
    public string Name { get; set; }

    [Required]
    public string CompanyName { get; set; }

    [MaxLength(3000)]
    public string Description { get; set; }

    [MaxLength(900)]
    public string WebPage { get; set; }

    public string Instagram { get; set; }
    public string Facebook { get; set; }

    [Required]
    public int IsNotVeganCount { get; set; } = 0;

    [Required]
    public int IsVeganCount { get; set; } = 0;

    [Required]
    public int RatingsCount { get; set; } = 0;

    public double? Rating { get; set; }

    [Required]
    public List<int> Tags { get; set; }

    public List<int> SecondaryTags { get; set; }

    public int? PricePoint { get; set; }

    public ICollection<VgnItmImageDbEntity> VgnItmImages { get; set; }

    public string Discriminator { get; set; }
}

public class VgnItmImageDbEntity : CreatedBySomeoneDbEntity
{
    [ForeignKey(nameof(VgnItm))]
    public int VgnItmId { get; set; }
    public VgnItmDbEntity VgnItm { get; set; }

    [ForeignKey(nameof(Image))]
    public int ImageId { get; set; }
    public ImageDbEntity Image { get; set; }
}

public class ImageDbEntity : CreatedBySomeoneDbEntity
{
    [Required]
    public Uri Url { get; set; }
    public List<int> Tags { get; set; }

    public ICollection<VgnItmImageDbEntity> VgnItmImages { get; set; } = new List<VgnItmImageDbEntity>();
}

public abstract class CreatedBySomeoneDbEntity : DbEntity<int>
{
    public string CreatedById { get; set; }
    public UserDbEntity CreatedBy { get; set; }
    public string UpdatedById { get; set; }
    public UserDbEntity UpdatedBy { get; set; }
}

public abstract class DbEntity<TId>
{
    [Key]
    public TId Id { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime UpdatedDate { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{ 
    var uriConverter = new ValueConverter<Uri, string>(
        v => v == null ? null : v.ToString(),
        v => v == null ? null : new Uri(v)
        );

    modelBuilder.Entity<ImageDbEntity>(image =>
    {
        image.Property(u => u.CreatedDate)
            .HasDefaultValueSql("CURRENT_TIMESTAMP");
        image.Property(u => u.UpdatedDate)
            .HasDefaultValueSql("CURRENT_TIMESTAMP");

        image.Property(i => i.Url)
            .HasConversion(uriConverter);
    });

    // Vegan Item Images
    modelBuilder.Entity<VgnItmImageDbEntity>(viImage => 
    { 
        viImage.HasKey(e => new { e.VgnItmId, e.ImageId }); 

        viImage.HasOne(e => e.VgnItm) 
            .WithMany(v => v.VgnItmImages) 
            .HasForeignKey(e => e.VgnItmId); 

        viImage.HasOne(e => e.Image) 
            .WithMany(i => i.VgnItmImages) 
            .HasForeignKey(e => e.ImageId); 

        viImage.HasIndex(g => new { g.VgnItmId, g.ImageId }).IsUnique(); 
        viImage.Property(e => e.Id).IsRequired().ValueGeneratedOnAdd(); 
        viImage.Property(u => u.CreatedDate) 
            .HasDefaultValueSql("CURRENT_TIMESTAMP"); 
        viImage.Property(u => u.UpdatedDate) 
            .HasDefaultValueSql("CURRENT_TIMESTAMP"); 
        viImage.HasOne(q => q.UpdatedBy) 
            .WithMany() 
            .HasForeignKey(k => k.UpdatedById); 
        viImage.HasOne(q => q.CreatedBy) 
            .WithMany() 
            .HasForeignKey(k => k.CreatedById); 
    }); 

    modelBuilder.Entity<VgnItmDbEntity>(vgnItm =>
    {
        vgnItm.HasIndex("CompanyName", "Name", "Discriminator").IsUnique();
        vgnItm.Property(e => e.Id).IsRequired().ValueGeneratedOnAdd();
        vgnItm.HasDiscriminator<string>("Discriminator")
            .HasValue<RecipeItmDbEntity>("RecipeItm")
            .HasValue<EventItmDbEntity>("EventItm")
            .HasValue<GroceryItmDbEntity>("GroceryItm")
            .HasValue<MenuItmDbEntity>("MenuItm")
            .HasValue<RestaurantItmDbEntity>("RestaurantItm")
            .HasValue<GroceryStoreItmDbEntity>("GroceryStoreItm")
            .HasValue<FashionItmDbEntity>("FashionItm");
        vgnItm.Property(u => u.CreatedDate)
            .HasDefaultValueSql("CURRENT_TIMESTAMP");
        vgnItm.Property(u => u.UpdatedDate)
            .HasDefaultValueSql("CURRENT_TIMESTAMP");
        vgnItm.HasKey(e => e.Id);
        vgnItm.HasOne(q => q.UpdatedBy)
            .WithMany()
            .HasForeignKey(k => k.UpdatedById);
        vgnItm.HasOne(q => q.CreatedBy)
            .WithMany()
            .HasForeignKey(k => k.CreatedById);
        vgnItm.HasMany(e => e.VgnItmImages)
            .WithOne()
            .OnDelete(DeleteBehavior.Cascade);
    });

    modelBuilder.Entity<RecipeItmDbEntity>(recipeItm =>
    {
        recipeItm.Property(e => e.Ingredients).HasColumnType("jsonb");
        recipeItm.Property(e => e.Method).HasMaxLength(100);
        recipeItm.Property(e => e.Tips).HasMaxLength(20);
        recipeItm.Property(e => e.Ingredients).HasMaxLength(100);
    });

    modelBuilder.Entity<SingleLocationVgnItmDbEntity>(singleLocationVgnItm =>
    {
        singleLocationVgnItm.HasIndex("CompanyName", "Name", "Discriminator", "LocationId").IsUnique();
        singleLocationVgnItm
        .HasOne(s => s.Location) // Each SingleLocationVgnItm has one Location.
        .WithMany() // A Location can be associated with many SingleLocationVgnItm.
        .HasForeignKey(s => s.LocationId); // Foreign key in SingleLocationVgnItm pointing to Location.
    });
}
解决方案

问题出在VgnItmDbEntity的导航属性配置上,你在OnModelCreating中配置HasMany(e => e.VgnItmImages).WithOne()时,未明确指定反向导航属性,导致EF Core无法正确关联已配置的外键,仍尝试生成默认列名。

修改VgnItmDbEntity的配置,在WithOne中指定反向导航属性,并显式指定外键列名:

modelBuilder.Entity<VgnItmDbEntity>(vgnItm =>
{
    // 保留原有其他配置...

    vgnItm.HasMany(e => e.VgnItmImages)
        .WithOne(v => v.VgnItm) // 指定反向导航属性
        .HasForeignKey(v => v.VgnItmId) // 显式指定外键列
        .OnDelete(DeleteBehavior.Cascade);
});

额外注意事项:

  • 删除之前手动修改的迁移文件,重新生成新迁移并更新数据库,确保迁移配置与实体映射一致
  • 清理项目编译缓存后重新编译
  • 确认数据库中VgnItmImages表的外键列确实为VgnItmId,且正确关联VgnItmDbEntity的Id列

完成以上操作后,EF Core即可正确识别数据库中的VgnItmId列,不再查找默认的VgnItmDbEntityId。

内容的提问来源于stack exchange,提问作者BeniaminoBaggins

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:05:05