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
相关产品推荐
相关产品推荐

