You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 16:30:56