代码之家  ›  专栏  ›  技术社区  ›  BeniaminoBaggins

更改EF Core生成的联接列的默认名称

  •  1
  • BeniaminoBaggins  · 技术社区  · 10 月前

    当此代码运行时(仅供参考 <TDbEntity> VgnItmDbEntity ):

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

    我得到错误:

    出现异常:CLR/Npgsql。引发PostgresException异常: 'Npgsql。系统中的PostgresException。私有的CoreLib.dll:'42703: 列v0.VgnItmDbEntityId不存在

    位置:1163' Npgsql。内部的NpgsqlConnector.d_233.MoveNext()
    在 系统运行时。编译器服务。PoolingAsyncValueTaskMethodBuilder 1.StateMachineBox 1.系统。线程。任务。来源。IValueTaskSource。GetResult(Int16 令牌)。NpgsqlDataReader.d__52.MoveNext()
    在Npgsql。位于的NpgsqlDataReader.d__52.MoveNext() Npgsql。NpgsqlCommand.d_119.MoveNext()位于 Npgsql。NpgsqlCommand.d_119.MoveNext()位于 Npgsql。NpgsqlCommand.d_112.MoveNext()位于 微软EntityFrameworkCore。存储关联命令.d_18.MoveNext() 在 微软EntityFrameworkCore。存储关联命令.d_18.MoveNext() 在 微软EntityFrameworkCore。查询内部的SingleQueryingEnumerable 1.AsyncEnumerator.<InitializeReaderAsync>d__21.MoveNext() at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.<ExecuteAsync>d__7 2.MoveNext() 在 微软EntityFrameworkCore。查询内部的SingleQueryingEnumerable 1.AsyncEnumerator.<MoveNextAsync>d__20.MoveNext() at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable 1.配置的ValueTaskAwaiter。GetResult() 在 微软EntityFrameworkCore。查询ShapedQueryCompilingExpressionVisitor.d__15 1.MoveNext() at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleOrDefaultAsync>d__15 1.MoveNext() 在Vepo。数据中的VgnItmsRepository`5.d__9.MoveNext() /用户/benjamifarquhar/dev/vepo_back_end/vepo。数据/存储库/VgnItms/VgnItms存储库.cs:line 144

    这些是我的实体及其在中的配置 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.
            });
    

    列名是实际的 VgnItmId VgnItmDbEntityId 。我不希望我的任何自动生成的EF Core列具有 DbEntity 在名称中。我不得不进行手动迁移以删除 VgnItmDbEntityId 列,但EF Core在代码中执行运行时查询时仍然认为它存在。

    如何让EF Core知道列的名称不是 VgnItmDbEntityId ,但更确切地说 VgnItmId ?

    我使用的是EF Core 8.0.4。我正在调查它是否是一个bug。

    This guy 有类似的问题,但我已经在使用他的解决方案 HasForeignKey 在onModelCreating中。

    1 回复  |  直到 10 月前
        1
  •  1
  •   Guru Stron    10 月前

    VgnItmDbEntity 尝试更改:

    vgnItm.HasMany(e => e.VgnItmImages)
        .WithOne() // potential problem
        .OnDelete(DeleteBehavior.Cascade);
    

    vgnItm.HasMany(e => e.VgnItmImages)
        .WithOne(entity => entity.VgnItm)
        .HasForeignKey(entity => entity.VgnItmId) // potentially not needed
        .OnDelete(DeleteBehavior.Cascade);
    

    您的代码有很多冗余TBH,首先,许多关系似乎应该由EF约定来处理。此外,您在两侧都定义了相同的关系(在一侧定义就足够了),然后通过属性也定义了(正如前面所写的那样,EF应该会自动拾取 SomePropNameId SomePropName 关系如果你不想依赖约定,并且尽可能明确-理想情况下,坚持一种描述模型的方式(流畅的API或属性),只从“一个方面”描述关系(即,在这种情况下,应用建议的更改并删除 viImage.HasOne(e => e.VgnItm)... ).

    我不得不进行手动迁移以删除VgnItmDbEntityId列,但EF Core在代码中执行运行时查询时仍然认为它存在。

    你不应该这样做。如果EF通过自定义迁移在其中生成一些结构更改名称,而不相应地更改模型,则不会影响EF对数据库的感知。