如何让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类型与转换器:
- 在项目根目录创建
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>" } ] }
- 重新运行原Scaffold命令,即可自动生成
int[]类型的Chests属性,并配置好对应的JSON转换器。
方法2:自定义Scaffolding模型工厂
如果配置文件方式不满足需求,可通过自定义IScaffoldingModelFactory来修改类型映射逻辑:
- 创建自定义模型工厂类:
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; } }
- 在项目服务配置中替换默认的模型工厂:
builder.Services.AddDbContext<SpckContext>(options => options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)) .ReplaceService<IScaffoldingModelFactory, CustomMySqlScaffoldingModelFactory>());
- 重新运行Scaffold命令,即可自动生成符合需求的实体类与配置。
注意事项
- 确保项目已安装
Pomelo.EntityFrameworkCore.MySql与Newtonsoft.Json(若使用Newtonsoft转换器);若偏好System.Text.Json,可替换转换器中的序列化/反序列化逻辑。 - 若使用
IList<int>而非int[],只需将上述配置中的int[]替换为IList<int>即可。
内容的提问来源于stack exchange,提问作者Jennal
相关产品推荐
相关产品推荐

