EF Core默认识别Id或实体名+Id为主键,也可用HasKey显式配置单主键(如.HasKey(p => p.Id))或复合主键(如.HasKey(oi => new { oi.OrderId, oi.ProductId })),配合ValueGeneratedOnAdd支持自增,列名需单独用HasColumnName设置。

EF Core 默认会自动识别 Id 或 实体类名 + Id(如 OrderId、ProductId)的属性作为主键,但你也可以显式配置——最常用、最灵活的方式就是 HasKey。
用 HasKey 配置单主键
在 OnModelCreating 中调用 HasKey,传入一个 Lambda 表达式指定主键属性:
modelBuilder.Entity().HasKey(p => p.Id); - 如果主键字段名不是
Id,比如叫ProductId,也一样写:.HasKey(p => p.ProductId) - 配合
ValueGeneratedOnAdd()可启用自增(适用于 SQL Server、MySQL 等支持 Identity 的数据库):modelBuilder.Entity().Property(p => p.Id).ValueGeneratedOnAdd();
用 HasKey 配置复合主键
复合主键必须用 Fluent API(数据注解不支持),语法是传入匿名类型:
modelBuilder.Entity().HasKey(oi => new { oi.OrderId, oi.ProductId }); - 这会在数据库中创建由两个字段组成的联合主键约束
- 注意:EF Core 会自动把这两个字段都设为非空(NOT NULL),且默认不加自增
- 不建议在大表(如超百万行)上长期使用复合主键,索引维护开销会上升
主键命名与数据库映射细节
HasKey 只负责定义“哪个字段/哪些字段是主键”,不控制列名或是否自增。列名需额外用 HasColumnName,自增行为要配 ValueGeneratedOnAdd 或数据注解:
- 改列名:
.Property(p => p.Id).HasColumnName("product_id") - 标记自增(数据注解方式):
[Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } - 主键类型支持
int、long、Guid,甚至string(但 string 主键无法自增,需手动赋值)
常见误区提醒
有些情况看似像主键配置,其实属于其他环节:
-
ToTable("xxx")是配表名,和主键无关 -
HasOne/WithMany配的是关系,外键字段需单独声明或靠约定推导 - 如果实体没定义任何主键,EF Core 会报错:“The entity type 'X' requires a primary key to be defined.”
- 拥有主键是 EF Core 跟踪实体变更的前提,无主键实体只能用
AsNoTracking()查询只读数据
基本上就这些。HasKey 是主键配置的核心入口,搭配 Property 方法可完成绝大多数场景,不需要过度依赖数据注解。










