\_Navigation 表是 EF Core 在未显式配置关系时自动创建的中间表,解决方法是:用 modelBuilder.Ignore() 忽略非实体导航属性,或用 HasOne/WithMany 显式配置关系,从模型源头阻止推断。
为什么 _Navigation 表在数据库里总被自动创建
这不是你手动建的,是某些 orm(比如 entity framework core)在启用导航属性但没显式配置关系时,自动生成的关联表。它不归你管,也不该出现在业务逻辑里——所以“隐藏”本质是不让它生成,而不是后期藏起来。
- EF Core 会扫描所有
public DbSet<T>和类中ICollection<T>类型的导航属性,一旦发现双向引用且没用[ForeignKey]或modelBuilder明确配置,就默认建_Navigation这种中间表 - PostgreSQL、SQL Server 都会出现,名字可能带下划线或驼峰(如
Blog_Posts),但 EF Core 6+ 默认倾向用_前缀命名 - 如果你看到迁移文件里有
CreateTable("..._Navigation", ...),说明模型推断已经失控了
用 modelBuilder.Ignore() 彻底跳过导航属性
最干净的办法:告诉 EF Core “这个属性别管,不是实体关系”。适用于你只是临时用 ICollection 做数据组装、并不需要数据库外键约束的场景。
- 在
OnModelCreating(ModelBuilder modelBuilder)里加:modelBuilder.Ignore<YourEntity>();——但这是忽略整个实体,慎用 - 更精准的是忽略特定导航属性:
modelBuilder.Entity<Blog>().Ignore(b => b.Posts); - 注意:忽略后,
Blog.Posts在查询中将始终为null,除非你手动赋值;不能用Include()加载 - 如果只是想禁用自动生成但保留加载能力,得走关系配置,不是 ignore
用 modelBuilder.Entity().HasOne().WithMany() 显式声明关系
这才是治本——让 EF Core 知道“你想怎么连”,它就不会瞎猜、不会造 _Navigation 表。
- 有外键字段时(推荐):
modelBuilder.Entity<Post>().HasOne(p => p.Blog).WithMany(b => b.Posts).HasForeignKey(p => p.BlogId); - 没外键字段但想建单向关系:必须用
.HasPrincipalKey()或指定DependentToPrincipal,否则仍可能 fallback 到影子外键 + 中间表 - 多对多必须显式配中间实体:EF Core 5+ 不再隐式支持无实体的多对多,
_Navigation就是它妥协的产物;正确做法是定义BlogPost实体并用两个HasOne配置 - 配完立刻删掉旧迁移,重新
dotnet ef migrations add FixNavigation,旧表才会消失
检查 DbContext 中的属性是否真需要导航
很多 _Navigation 表源于“看起来像关系,其实只是 DTO 或 View Model 里的集合”。这类字段根本不该进 DbSet 或参与模型构建。
- 确认
Posts是public ICollection<Post> Posts { get; set; }还是public List<Post> Posts { get; set; }——后者在 EF Core 中也可能触发推断 - DTO 类、ViewModel 类、API 请求/响应类,绝对不要继承
DbContext或塞进DbSet;用[NotMapped]标记非映射属性 - 如果用了 AutoMapper,检查
CreateMap<Blog, BlogDto>()是否意外把导航属性也映射了,导致生成逻辑误判 - 运行时看 EF 日志:
options.LogTo(Console.WriteLine),搜索Detected relationship能看到它到底基于什么推断出了关系
[NotMapped] 的集合、一次漏掉的 HasForeignKey、甚至属性名大小写不一致,都可能导致 _Navigation 表悄悄出现。真正要“隐藏”,得从模型定义源头掐断推断路径,而不是等表建出来再想办法藏。

















