如何在EF Core Code First模式下将主键从GUID改为int?
EF Core Code First下将GUID主键改为Int的实践方案(千万级数据场景)
针对SQL Server中10-20百万条数据的遗留库,直接修改主键类型风险极高,必须分阶段平滑过渡,避免锁表和业务中断,以下是可落地的步骤:
1. 准备阶段:新增Int列并填充数据
- 在实体类中添加可空Int类型的临时主键列,比如
NewId:public Guid Id { get; set; } // 原GUID主键 public int? NewId { get; set; } // 新增临时列 - 生成EF Core迁移并执行,在数据库中新增
NewId列,设置为自增列(SQL Server会自动为现有百万条数据填充连续的Int值)。这一步务必在业务低峰期操作,避免IO过载。
2. 双写阶段:同步新老主键数据
- 修改业务代码,新增实体时同时维护原GUID主键和
NewId(依赖数据库自增的话无需手动赋值);更新操作不修改NewId,仅保留原有逻辑的同时确保NewId值稳定。 - 这一阶段持续运行1-2个业务周期,确保所有新数据都有
NewId,同时验证读写逻辑无异常。
3. 关联表适配:同步外键数据
- 若当前表存在外键关联其他表,给每个关联表新增对应的
NewXXXId列(比如主表是User,关联表Order新增NewUserId)。 - 分批更新关联表的新外键列,每次更新1000条数据,避免长时间锁表:
WHILE EXISTS(SELECT 1 FROM Order WHERE NewUserId IS NULL) BEGIN UPDATE TOP(1000) o SET o.NewUserId = u.NewId FROM Order o JOIN User u ON o.UserId = u.Id WHERE o.NewUserId IS NULL END - 给所有
NewId列添加唯一非聚集索引,确保数据唯一性,为后续切换主键做准备。
4. 切换主键:替换GUID为Int
- 先将
NewId列改为非空(此时所有数据已填充值),生成并执行迁移:public int NewId { get; set; } // 去掉可空标记 - 修改实体类的主键配置,移除原GUID列的
[Key]特性,给NewId加上[Key]:// [Key] 注释掉原主键标记 public Guid Id { get; set; } [Key] public int NewId { get; set; } - 手动修改EF Core生成的迁移文件,避免自动生成的高风险操作:
// 先删除原主键约束 migrationBuilder.DropPrimaryKey( name: "PK_YourTableName", table: "YourTableName"); // 添加新主键约束 migrationBuilder.AddPrimaryKey( name: "PK_YourTableName", table: "YourTableName", column: "NewId"); - 在低峰期执行该迁移,期间监控数据库锁表情况。
5. 清理阶段:移除冗余数据
- 确认所有业务代码已完全切换到使用
NewId作为主键后,逐步删除原GUID主键列、关联表的旧外键列,以及对应的冗余索引。 - 清理操作同样分批执行,避免影响业务。
关键注意事项
- 所有操作前必须全量备份数据库,防止数据丢失。
- 批量更新、主键切换等操作必须在业务低峰期执行,必要时可短暂只读降级。
- 若为分布式系统,需改用全局唯一的Int生成策略(如雪花算法)替代自增列,避免主键冲突。
内容的提问来源于stack exchange,提问作者kaushal sharma
相关产品推荐
相关产品推荐

