.NET WebAPI中JSON数组转C#对象的EF Core序列化与迁移问题求助
问题
我正在构建一个通过POST操作接收JSON的.NET WebAPI,接收的JSON格式如下:
{ "site": "00131231201d010231", "publishTime": 123123123123, "domains": [ "example.com" ], "publishedBy": { "name": "John Doe", "id": "00211231201d010231" } }
我将JSON映射为如下C#对象:
public class Project { [Key] [JsonPropertyName("site")] public string Site { get; set; } [JsonPropertyName("publishTime")] public long PublishTime { get; set; } [JsonPropertyName("domains")] public List<Domain> Domains { get; set; } [JsonPropertyName("publishedBy")] public PublishedBy PublishedBy { get; set; } } public class PublishedBy { [JsonPropertyName("name")] public string Name { get; set; } [Key] [JsonPropertyName("id")] public string Id { get; set; } } public class Domain { [Key] public string Id { get; set; } public string Name { get; set; } }
我的目标是将内容存入数据库,但使用List<string>作为Domains类型时,EF Core迁移报错,提示无法使用字符串类型。于是我创建了Domain类,但此时反序列化时出现错误:
System.Text.Json.JsonException: The JSON value could not be converted to spine_management.Models.Domain.
请问Domains应设置为何种类型,以及最佳的反序列化方式是什么?注:我希望保留domains属性,不希望忽略或删除它。
解决方案
针对你的问题,有两种可行的处理方式,既能满足EF Core的数据库存储要求,又能正确完成JSON反序列化:
方式一:自定义JSON转换器
保留List<Domain>类型,通过自定义JsonConverter实现字符串到Domain对象的自动转换:
- 创建自定义转换器:
public class DomainConverter : JsonConverter<Domain> { public override Domain Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 将JSON字符串映射为Domain的Name和Id(可根据需求调整Id生成逻辑) var domainName = reader.GetString(); return new Domain { Id = domainName, Name = domainName }; } public override void Write(Utf8JsonWriter writer, Domain value, JsonSerializerOptions options) { // 序列化时输出Name字段的字符串值 writer.WriteStringValue(value.Name); } }
- 在Project类的Domains属性上添加转换器标记:
[JsonPropertyName("domains")] [JsonConverter(typeof(DomainConverter))] public List<Domain> Domains { get; set; }
这样反序列化时,JSON中的字符串数组会自动转为List<Domain>,同时EF Core可以正常识别Domain实体进行迁移和存储。
方式二:拆分属性(兼顾序列化和EF存储)
在Project类中同时定义两个属性:一个用于JSON反序列化的List<string>,另一个用于EF存储的List<Domain>,通过属性逻辑自动同步:
public class Project { [Key] [JsonPropertyName("site")] public string Site { get; set; } [JsonPropertyName("publishTime")] public long PublishTime { get; set; } // 仅用于JSON反序列化,不映射到数据库 [JsonPropertyName("domains")] public List<string> DomainNames { get; set; } // 用于EF Core存储,忽略JSON序列化 [JsonIgnore] public List<Domain> Domains { get; set; } [JsonPropertyName("publishedBy")] public PublishedBy PublishedBy { get; set; } // 反序列化完成后自动同步数据 [OnDeserialized] private void OnDeserialized(StreamingContext context) { if (DomainNames != null) { Domains = DomainNames.Select(name => new Domain { Id = name, Name = name }).ToList(); } } }
这种方式通过分离序列化和存储的属性,避免了转换器的复杂逻辑,同时保证两端需求都能满足。
补充说明
- 关于Domain类的Id字段:如果不想用域名作为Id,可以自行生成唯一标识(比如Guid),只需要在转换器或同步逻辑中调整Id的赋值即可。
- EF Core迁移时,确保Domain类的配置正确(比如通过Fluent API设置主键关系),避免实体映射错误。
内容的提问来源于stack exchange,提问作者Dechaun Bakker
相关产品推荐
相关产品推荐

