修改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
相关产品推荐
相关产品推荐

