EF Core 对 Guid 主键有原生支持,默认就会按客户端生成方式处理,不需要额外配置就能用,但要真正用好,得清楚几种生成策略的区别和适用场景。
默认客户端生成(最常用)
只要实体类主键属性是 Guid 类型、名字叫
Id或
实体名+Id(比如
UserId),EF Core 就会自动把它识别为主键,并启用
ValueGeneratedOnAdd()—— 也就是在调用
Add()时,由 .NET 客户端生成
Guid.NewGuid(),再插入数据库。 无需加任何特性或 Fluent API 配置 插入前 ID 已确定,适合离线场景或需要提前知道 ID 的逻辑(比如生成 URL、发消息) 不依赖数据库连接,高并发安全
数据库端生成(SQL Server / PostgreSQL / MySQL 各有写法)
如果希望数据库负责生成 Guid(比如用 SQL Server 的
NEWID()或
NEWSEQUENTIALID()),就得在
OnModelCreating中显式配置: SQL Server:用
.HasDefaultValueSql("NEWID()")(随机)或 "NEWSEQUENTIALID()"(顺序,减少索引碎片) PostgreSQL:用
.HasDefaultValueSql("gen_random_uuid()")(需启用 pgcrypto扩展) MySQL:用
.HasDefaultValueSql("uuid()")
注意:必须搭配 .ValueGeneratedOnAdd(),否则 EF 不会跳过赋值
禁用自动生成(手动控制)
如果你要在代码里完全自己控制 Guid 值(比如从外部系统传入、或复用旧数据),就用这个方式:
加特性[DatabaseGenerated(DatabaseGeneratedOption.None)]或者 Fluent API 写
.ValueGeneratedNever()之后每次
Add()前必须显式赋值
Id = ...,否则会存
00000000-...导致重复或约束失败
性能提醒:别把 Guid 当聚集索引
Guid 是 16 字节、无序的,直接设为主键 + 聚集索引会导致严重索引碎片,尤其在高写入场景下:
SQL Server:避免用NEWID()+ 聚集主键;可用
NEWSEQUENTIALID()缓解,但仍建议非聚集主键 + 单独添加自增列作聚集索引 MySQL(InnoDB):主键强制聚集,所以不推荐用 Guid 做主键;如必须用,考虑加
id BIGINT AUTO_INCREMENT PRIMARY KEY作聚集索引,Guid 字段单独建唯一非聚集索引 所有情况:确保查询常用字段上有合适索引,别只靠主键索引查数据
基本上就这些。选哪种策略,关键看你要不要离线生成、是否在意索引性能、用的是什么数据库——不是越“高级”的方案越好,而是匹配你的实际部署和读写模式。
