EF Core 8:JSON自有列列名改为驼峰命名的问题求助
解决EF Core 8中PostgreSQL Jsonb列名未驼峰转换的问题
核心问题原因
你遇到的问题是:使用ToJson()将Owned实体映射为PostgreSQL Jsonb列时,EF Core默认使用C#属性的帕斯卡命名(ShippingAddress)作为数据库列名,但你的数据库要求驼峰命名(shippingAddress),而全局的ConfigureCamelCase配置没有处理这种Owned导航对应的Json列名,导致查询时找不到列,迁移生成的列名也不符合规范。
快速解决方案:指定Json列名
直接使用ToJson()的重载方法,显式指定数据库中的Json列名为驼峰格式,修改OnModelCreating中的配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<OrderEntity>().OwnsOne( order => order.ShippingAddress, ownedNavigationBuilder => { // 直接指定Json列的数据库名称为驼峰 ownedNavigationBuilder.ToJson("shippingAddress"); ownedNavigationBuilder.OwnsOne(shippingAddress => shippingAddress.Country); ownedNavigationBuilder.OwnsOne(shippingAddress => shippingAddress.Company); }); modelBuilder.ConfigureCamelCase(); }
重新生成迁移后,Json列的名称会变为shippingAddress,查询时就不会出现列不存在的错误。
全局批量解决方案:修改ConfigureCamelCase扩展
如果你有多个Json列需要统一处理,可以修改你的ConfigureCamelCase扩展方法,让它自动将所有Owned Json列的名称转为驼峰:
public static class ModelBuilderExtensions { public static void ConfigureCamelCase(this ModelBuilder modelBuilder) { // 处理表名、普通属性列名、约束名(原有逻辑保留) foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { // 表名转驼峰 entityType.SetTableName(entityType.GetTableName()?.ToCamelCase() ?? entityType.DisplayName()); // 普通属性列名转驼峰 foreach (var property in entityType.GetProperties()) { property.SetColumnName(property.Name.ToCamelCase()); } // 主键、外键、索引名转驼峰(按需保留) foreach (var key in entityType.GetKeys()) { key.SetName(key.GetName()?.ToCamelCase()); } foreach (var foreignKey in entityType.GetForeignKeys()) { foreignKey.SetConstraintName(foreignKey.GetConstraintName()?.ToCamelCase()); } foreach (var index in entityType.GetIndexes()) { index.SetDatabaseName(index.GetDatabaseName()?.ToCamelCase()); } } // 新增:处理Owned Json列的列名 foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { foreach (var navigation in entityType.GetNavigations()) { // 判断是否是Json存储的Owned实体 if (navigation.TargetEntityType.IsOwned() && navigation.TargetEntityType.IsJsonOwned()) { var jsonColumnInfo = navigation.TargetEntityType.FindAnnotation("Relational:JsonColumnInfo"); if (jsonColumnInfo?.Value is JsonColumnInfo jsonColumn) { // 将Json列名转为驼峰 jsonColumn.Column.SetColumnName(navigation.Name.ToCamelCase()); } } } } } // 判断实体是否是Json存储的Owned类型 private static bool IsJsonOwned(this IEntityType entityType) { return entityType.FindAnnotation("Relational:JsonColumnInfo") != null; } // 字符串转驼峰的辅助方法 public static string ToCamelCase(this string input) { if (string.IsNullOrEmpty(input)) return input; return char.ToLowerInvariant(input[0]) + input.Substring(1); } }
修改后,所有使用ToJson()的Owned导航对应的Json列都会自动转为驼峰命名,无需逐个手动配置。
为什么你之前的尝试无效?
- 方法1、2:
JsonSerializerOptions控制的是Json内容内部属性的序列化规则(比如FirstName转firstName),和数据库列名无关,因此对列名没有影响。 - 方法3、4:
[Column]注解和HasColumnName需要针对普通属性使用,但ShippingAddress是导航属性,不是普通属性,EF Core不会处理这些配置。 - 方法5:
ToTable和ExcludeFromMigrations是针对Owned实体生成独立表的场景,而ToJson是将Owned实体嵌入主表的Json列,这些配置不适用。 - 方法6、7:
SetField是设置C#属性对应的后台字段名称,不是数据库列名,你的实体中没有shippingAddress字段,因此报错,方向完全错误。
内容的提问来源于stack exchange,提问作者Rémi Lamotte
相关产品推荐
相关产品推荐

