C#使用Newtonsoft.Json反序列化动态键JSON并提取数据存SQL的方法
动态键JSON反序列化与结构化存库实现方法
问题本质
你之前尝试用json.result.inside.????.alt的点号路径无法取值,是因为result.inside下的子节点键名是无固定规则的动态字符串(比如示例中的MMLEHH-YUR、OZWVHR-N3ED4-CM3ACG),不存在和C#固定属性名的匹配关系,根本无法通过写死的点语法访问到具体节点。
Newtonsoft.Json反序列化得到的dynamic对象实际类型是JObject,本身支持以键值对方式遍历所有动态属性,不需要提前获知具体键名。
- 如果已经提前确定某个固定键名,也可以通过索引器语法灵活取值,比如
insideNode["MMLEHH-YUR"]["alt"],但接口返回的键是动态变化时,这种方式不再适用,必须遍历所有属性节点。
实现步骤
1. 定义匹配存储需求的强类型结构
按照你期望的字段格式,定义对应的数据类,后续可直接和SQL表字段做映射,避免运行时拆包引发的类型错误:
/// <summary>映射到SQL表的结构化数据类</summary> public class SqlTargetRecord { /// <summary>对应动态键名,如 MMLEHH-YUR</summary> public string Global { get; set; } public object Id { get; set; } public int Number { get; set; } public string Alt { get; set; } public decimal Price { get; set; } public decimal Price2 { get; set; } public string State { get; set; } public string Vol { get; set; } public string Misc { get; set; } }
2. 遍历动态节点提取结构化数据
不需要写死每个动态键的访问路径,直接遍历inside节点下的所有属性,逐笔提取字段值:
using Newtonsoft.Json.Linq; using System.Collections.Generic; // 解析接口返回的JSON字符串 JObject fullJson = JObject.Parse(jsonResponse); var recordList = new List<SqlTargetRecord>(); // 定位到 result > inside 节点 JObject insideNode = fullJson["result"]?["inside"] as JObject; if (insideNode == null) return; // 遍历inside下所有动态命名的键值对 foreach (JProperty itemProp in insideNode.Properties()) { // 键名就是需要存入Global字段的值 string globalKeyValue = itemProp.Name; // 键对应的对象值就是包含业务字段的节点 JObject itemDataNode = itemProp.Value as JObject; if (itemDataNode == null) continue; // 逐字段映射到强类型结构 var currentRecord = new SqlTargetRecord { Global = globalKeyValue, Id = itemDataNode["id"]?.ToObject<object>(), Number = itemDataNode["number"]?.ToObject<int>() ?? 0, Alt = itemDataNode["alt"]?.ToObject<string>(), Price = itemDataNode["descr"]?["price"]?.ToObject<decimal>() ?? 0, Price2 = itemDataNode["descr"]?["price2"]?.ToObject<decimal>() ?? 0, State = itemDataNode["descr"]?["state"]?.ToObject<string>(), Vol = itemDataNode["vol"]?.ToObject<string>(), Misc = itemDataNode["misc"]?.ToObject<string>() }; recordList.Add(currentRecord); }
注意事项
- 提取阶段就完成类型转换,比如把JSON里字符串格式的价格(如
"4.33000")直接转成SQL支持的decimal类型,避免存库时出现类型不匹配错误。 - 提取完成后得到的
recordList是标准强类型集合,可以直接配合ADO.NET、Dapper、EF Core等数据访问组件,逐笔写入SQL数据库,不需要再处理dynamic对象的拆包逻辑。 - 所有节点取值时必须加空值判断,避免接口返回字段缺失时触发空引用异常。
内容的提问来源于stack exchange,提问作者Jerome Bellegarde
相关产品推荐
相关产品推荐

