EF Core 2中拥有实体的自定义主键名称未存入ModelSnapshot问题
解决EF Core 2.0 + Npgsql中拥有类型主键命名重复迁移的问题
我之前也踩过EF Core 2.0搭配Npgsql这个坑,尤其是值对象(拥有类型)的主键命名不匹配导致每次迁移都重复修改的问题,给你几个实用的解决思路:
1. 手动修正ModelSnapshot文件
问题的核心是ModelSnapshot里没有正确记录数据库中已经存在的蛇形主键名(pk_foo),而是保留了默认的驼峰式主键名(PK_foo)。你可以直接修改快照文件:
- 找到项目中的
YourDbContextModelSnapshot.cs文件 - 定位到对应拥有类型的配置代码块,比如:
modelBuilder.Entity<Order>(b => { b.OwnsOne(e => e.ShippingAddress, b => { b.HasKey("Id"); b.Property("Id").ValueGeneratedOnAdd(); b.HasConstraintName("PK_ShippingAddress"); // 这里是问题所在 }); }); - 将
HasConstraintName("PK_ShippingAddress")改成HasConstraintName("pk_shipping_address")(对应你的蛇形命名规则) - 保存后再生成新迁移,就不会再出现重复修改主键名的操作了
2. 全局配置拥有类型的主键命名规则
如果不想每次都手动改快照,可以在OnModelCreating里添加全局配置,确保所有拥有类型的主键都自动应用蛇形命名:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 先应用其他默认配置或自定义配置 base.OnModelCreating(modelBuilder); // 遍历所有拥有类型的主键,统一转成蛇形命名 var snakeCaseTranslator = new NpgsqlSnakeCaseNameTranslator(); modelBuilder.Model.GetEntityTypes() .Where(t => t.IsOwned()) .SelectMany(t => t.GetKeys()) .ToList() .ForEach(key => { var originalName = key.Relational().Name; key.Relational().Name = snakeCaseTranslator.TranslateName(originalName); }); }
这段代码会自动把所有拥有类型的主键约束名转成蛇形,确保ModelSnapshot生成时就用正确的命名,和数据库状态保持一致。
3. 升级EF Core版本(推荐)
EF Core 2.0本身存在不少和Npgsql适配的bug,后续的2.1及以上版本已经修复了拥有类型命名约定的问题。如果你的项目允许升级依赖,直接把EF Core和Npgsql.EntityFrameworkCore.PostgreSQL升级到2.1或更高版本,默认的蛇形命名配置就能正确覆盖拥有类型的主键,从根源上解决这个问题。
注意事项
- 修改ModelSnapshot后,一定要确认当前数据库的主键名和快照中的一致,避免后续迁移出现冲突
- 全局配置要放在
OnModelCreating的合适位置,确保在其他实体配置之后执行(或者根据你的配置顺序调整) - 升级EF Core版本前,建议先在测试环境验证兼容性,因为2.0到2.1有部分API变动
内容的提问来源于stack exchange,提问作者Bonnotbh
相关产品推荐
相关产品推荐

