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

EF Core 7:.ToJson()与HasConversion的适用场景及正确用法

EF Core 存储JSON时字典被二次序列化的问题解决

问题场景

我需要让数据库列存储标准JSON格式,DTO结构如下:

public class GoesToDb
{
    public int Id { get; set; }
    public List<MatchSuccess> MatchSuccesses { get; set; } = new List<MatchSuccess>();
    public List<MatchFailure> MatchFailures { get; set; } = new List<MatchFailure>();
}

public class MatchSuccess
{
    public MatchSuccess()
    {
        Meta = new Dictionary<string, string>();
    }
   
    public string Foo { get; set; }
    public string Bar { get; set; }
    public Dictionary<string, string> Meta { get; set; }
}

public class MatchFailure
{
    public string Foo { get; set; }
    public string Bar { get; set; }
}

尝试将MatchSuccess存储为JSON字符串时,Meta字典出现二次序列化问题。当前配置能运行,但数据库中存储的JSON格式混乱,无法轻松解析:

期望存储格式

"MatchSuccesses": [
    {
        "Foo": "888",
        "Bar": "236129",
        "Meta": {
            "Item1": "236129"
        }
    }
]

实际存储结果

[{"Meta":"{"Item1":"236129"}","Foo":"236129","Bar":"888"}]

当前的ContextBuilder配置:

modelBuilder.Entity<GoesToDb>(entity =>
{
    entity.OwnsMany(e => e.MatchSuccesses, builder =>
    {
        builder.ToJson();
        builder.Property(p => p.Meta)
            .HasConversion(
                v => JsonSerializer.Serialize(v, options),
                v => JsonSerializer.Deserialize<Dictionary<string, string>>(v, options));
    
    });
    entity.OwnsMany(e => e.MatchFailures, b =>
    {
        b.ToJson();
    });
});

解决方法

问题根源是同时使用ToJson()和手动HasConversion序列化,导致Meta被二次序列化:

  • ToJson()会自动处理整个MatchSuccess对象的JSON序列化,包括其中的Dictionary类型属性
  • 手动给Meta添加的HasConversion会先把字典序列化成字符串,后续ToJson()又将该字符串作为普通JSON值存储,最终造成嵌套JSON字符串的问题

只需要移除Meta属性的HasConversion配置即可:

modelBuilder.Entity<GoesToDb>(entity =>
{
    entity.OwnsMany(e => e.MatchSuccesses, builder =>
    {
        // 仅保留ToJson(),EF Core会自动处理Dictionary的序列化
        builder.ToJson();
    });
    entity.OwnsMany(e => e.MatchFailures, b =>
    {
        b.ToJson();
    });
});

如果需要自定义JSON序列化规则,可通过两种方式实现:

  • 全局配置EF Core的JSON序列化器(在DbContext的OnConfiguring方法中):
optionsBuilder.UseSqlServer(connectionString, sqlOptions =>
{
    sqlOptions.UseJsonSerializerOptions(new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = true
    });
});
  • 针对特定ToJson()配置序列化选项:
entity.OwnsMany(e => e.MatchSuccesses, builder =>
{
    builder.ToJson(options =>
    {
        options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 11:27:31