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

如何让dotnet-ef scaffold自动映射MySQL JSON为int[]/IList<int>?

如何让EF Core Scaffold自动将MySQL JSON字段映射为C#数组类型?

问题场景

现有MySQL表user_chapter,其中chests字段为JSON类型,存储值格式如"[1, 2, 3]"(整数数组的JSON字符串)。使用dotnet ef dbcontext scaffold命令生成实体类时,该字段默认被映射为string类型,希望实现自动映射为C#的int[]或IList<int>类型,避免手动修改代码。

现有表结构

CREATE TABLE IF NOT EXISTS `spck`.`user_chapter` (
  `user_id` INT NOT NULL,
  `chapter_id` INT NOT NULL,
  `chests` JSON NOT NULL,
  PRIMARY KEY (`user_id`, `chapter_id`))
ENGINE = InnoDB;

当前使用的Scaffold命令

dotnet ef dbcontext scaffold "Server=127.0.0.1;Port=3306;Database=spck;User=root;Password=;TreatTinyAsBoolean=true;" "Pomelo.EntityFrameworkCore.MySql" -o Generated/ -f

默认生成的实体类与配置

生成的UserChapter实体类:

public partial class UserChapter
{
    public int UserId { get; set; }
    public int ChapterId { get; set; }
    public string Chests { get; set; } = null!;
}

对应的DbContext配置:

modelBuilder.Entity<UserChapter>(entity =>
{
    entity.HasKey(e => new { e.UserId, e.ChapterId })
        .HasName("PRIMARY")
        .HasAnnotation("MySql:IndexPrefixLength", new[] { 0, 0 });

    entity.ToTable("user_chapter");

    entity.Property(e => e.UserId).HasColumnName("user_id");

    entity.Property(e => e.ChapterId).HasColumnName("chapter_id");

    entity.Property(e => e.Chests)
        .HasColumnType("json")
        .HasColumnName("chests");
});

手动修改后的目标代码

修改后的实体类:

public partial class UserChapter
{
    public int UserId { get; set; }
    public int ChapterId { get; set; }
    public int[] Chests { get; set; } = null!;
}

添加类型转换后的DbContext配置:

modelBuilder.Entity<UserChapter>(entity =>
{
    entity.HasKey(e => new { e.UserId, e.ChapterId })
        .HasName("PRIMARY")
        .HasAnnotation("MySql:IndexPrefixLength", new[] { 0, 0 });

    entity.ToTable("user_chapter");

    entity.Property(e => e.UserId).HasColumnName("user_id");

    entity.Property(e => e.ChapterId).HasColumnName("chapter_id");

    entity.Property(e => e.Chests)
        .HasColumnType("json")
        .HasColumnName("chests")
        .HasConversion<int[]>(str => JsonConvert.DeserializeObject<int[]>(str) ?? Array.Empty<int>(), list => JsonConvert.SerializeObject(list));
});

自动映射的解决方案

方法1:使用配置文件指定类型映射

通过efpt.config.json配置文件(EF Core Scaffold会读取该文件),直接指定JSON类型字段对应的CLR类型与转换器:

  1. 在项目根目录创建efpt.config.json文件,填入以下内容(替换YourProjectNamespace为实际项目命名空间):
{
  "CodeGenerationMode": 3,
  "ContextClassName": "SpckContext",
  "OutputContextPath": "Generated",
  "OutputPath": "Generated",
  "PreserveCasingWithRegex": true,
  "ProjectRootNamespace": "YourProjectNamespace",
  "Tables": [
    {
      "Name": "`spck`.`user_chapter`",
      "ObjectType": 0
    }
  ],
  "UseFluentApiOnly": true,
  "TypeMappingOverrides": [
    {
      "StoreTypeName": "json",
      "ClrTypeName": "int[]",
      "ConverterName": "NewtonsoftJsonArrayConverter<int>"
    }
  ]
}
  1. 重新运行原Scaffold命令,即可自动生成int[]类型的Chests属性,并配置好对应的JSON转换器。

方法2:自定义Scaffolding模型工厂

如果配置文件方式不满足需求,可通过自定义IScaffoldingModelFactory来修改类型映射逻辑:

  1. 创建自定义模型工厂类:
using Microsoft.EntityFrameworkCore.Scaffolding;
using Microsoft.EntityFrameworkCore.Metadata;
using Pomelo.EntityFrameworkCore.MySql.Scaffolding.Internal;
using Newtonsoft.Json;

public class CustomMySqlScaffoldingModelFactory : MySqlScaffoldingModelFactory
{
    public CustomMySqlScaffoldingModelFactory(IScaffoldingModelFactoryDependencies dependencies) 
        : base(dependencies)
    {
    }

    public override IModel Create(string connectionString, IEnumerable<string> tables, IEnumerable<string> schemas, string namespaceName, string contextName, ModelReverseEngineerOptions options)
    {
        var model = base.Create(connectionString, tables, schemas, namespaceName, contextName, options);
        
        // 定位目标表与字段
        var userChapterEntity = model.FindEntityType("spck.user_chapter");
        if (userChapterEntity != null)
        {
            var chestsProperty = userChapterEntity.FindProperty("chests");
            if (chestsProperty != null)
            {
                // 修改CLR类型为int[]
                chestsProperty.SetClrType(typeof(int[]));
                // 添加JSON转换逻辑
                chestsProperty.SetValueConverter(
                    new ValueConverter<int[], string>(
                        value => JsonConvert.SerializeObject(value),
                        value => JsonConvert.DeserializeObject<int[]>(value) ?? Array.Empty<int>())
                );
            }
        }
        
        return model;
    }
}
  1. 在项目服务配置中替换默认的模型工厂:
builder.Services.AddDbContext<SpckContext>(options =>
    options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))
           .ReplaceService<IScaffoldingModelFactory, CustomMySqlScaffoldingModelFactory>());
  1. 重新运行Scaffold命令,即可自动生成符合需求的实体类与配置。

注意事项

  • 确保项目已安装Pomelo.EntityFrameworkCore.MySql与Newtonsoft.Json(若使用Newtonsoft转换器);若偏好System.Text.Json,可替换转换器中的序列化/反序列化逻辑。
  • 若使用IList<int>而非int[],只需将上述配置中的int[]替换为IList<int>即可。

内容的提问来源于stack exchange,提问作者Jennal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:24:32