EntityFrameworkCore如何为多对多隐式生成的关联表新增自定义列并解决映射报错
问题原因
你的报错是因为同时配置了两套多对多映射,二者冲突导致:
- 一套是Blog和Post之间的隐式多对多(
HasMany(x => x.Posts).WithMany(x => x.Blogs)),EF Core会自动生成一个影子类型的关联实体映射到BlogPost表 - 另一套是你手动定义的BlogPost实体也映射到同一个BlogPost表
解决方法
方案1:使用显式多对多关联实体(推荐,自定义字段灵活度更高)
步骤1:修改关联实体,添加Order字段
public class BlogPost { public long BlogsId { get; set; } public Blog Blog { get; set; } public long PostsId { get; set; } public Post Post { get; set; } // 新增所需的Order列 public int Order { get; set; } }
步骤2:调整Blog和Post实体的导航属性
可以删除原来的直接多对多导航,只保留到关联实体的导航:
public class Blog { public long Id { get; set; } public string Content { get; set; } // 删掉原来的ICollection<Post> Posts属性 public ICollection<BlogPost> BlogPosts { get; set; } = new List<BlogPost>(); } public class Post { public long Id { get; set; } public string Content { get; set; } // 删掉原来的ICollection<Blog> Blogs属性 public ICollection<BlogPost> BlogPosts { get; set; } = new List<BlogPost>(); }
如果需要保留原来的直接导航(比如blog.Posts直接获取关联的Post列表),也可以保留,后续配置时做关联即可。
步骤3:修改OnModelCreating配置
删掉原来的隐式多对多配置,替换为显式多对多配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 配置联合主键 modelBuilder.Entity<BlogPost>() .HasKey(x => new { x.BlogsId, x.PostsId }); // 配置Blog到关联实体的关系 modelBuilder.Entity<BlogPost>() .HasOne(x => x.Blog) .WithMany(x => x.BlogPosts) .HasForeignKey(x => x.BlogsId); // 配置Post到关联实体的关系 modelBuilder.Entity<BlogPost>() .HasOne(x => x.Post) .WithMany(x => x.BlogPosts) .HasForeignKey(x => x.PostsId); // 如果保留了Blog和Post之间的直接导航,添加下方配置做关联 // modelBuilder.Entity<Blog>() // .HasMany(x => x.Posts) // .WithMany(x => x.Blogs) // .UsingEntity<BlogPost>( // l => l.HasOne<Post>().WithMany().HasForeignKey(x => x.PostsId), // r => r.HasOne<Blog>().WithMany().HasForeignKey(x => x.BlogsId) // ); }
方案2:不手动定义关联实体,通过隐式多对多添加Payload字段(EF Core 5+支持)
如果不想显式定义BlogPost实体,也可以直接在隐式多对多配置中添加额外字段:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Blog>() .HasMany(x => x.Posts) .WithMany(x => x.Blogs) .UsingEntity<Dictionary<string, object>>( "BlogPost", b => b.HasOne<Post>().WithMany().HasForeignKey("PostsId"), p => p.HasOne<Blog>().WithMany().HasForeignKey("BlogsId"), j => { // 新增Order字段 j.Property<int>("Order"); j.HasKey("BlogsId", "PostsId"); }); }
这种方式下操作Order字段需要通过ChangeTracker或者关联集合的Entry操作,灵活度低于显式定义关联实体的方案。
内容的提问来源于stack exchange,提问作者Vuk Isic
相关产品推荐
相关产品推荐

