如何反序列化JSON并合并行数不一致的数据至DataTable主记录
解决DataTable中多行JSON数据与主记录的合并问题
核心问题在于主表行与JSON反序列化后的数据行需要明确关联逻辑:当JSON是数组(多行)时,主表的一行需要扩展为多行,每行对应JSON数组中的一条记录;当JSON是单个对象(单行)时,直接合并到主表当前行。以下是支持多JSON列、自动处理行数不一致的实现方案:
实现步骤与代码
1. 核心合并方法
封装通用方法,负责将单行主记录与某列的JSON反序列化数据合并:
using Newtonsoft.Json; using System.Data; public static List<DataRow> MergeJsonToRow(DataRow mainRow, string jsonColumnName, string jsonColumnPrefix = "") { var resultRows = new List<DataRow>(); string jsonData = mainRow[jsonColumnName]?.ToString(); if (string.IsNullOrWhiteSpace(jsonData)) { // JSON为空,返回原行副本 var emptyRow = mainRow.Table.NewRow(); mainRow.ItemArray.CopyTo(emptyRow.ItemArray, 0); resultRows.Add(emptyRow); return resultRows; } // 反序列化JSON为DataTable DataTable jsonDt = JsonConvert.DeserializeObject<DataTable>(jsonData); if (jsonDt == null || jsonDt.Rows.Count == 0) { var emptyRow = mainRow.Table.NewRow(); mainRow.ItemArray.CopyTo(emptyRow.ItemArray, 0); resultRows.Add(emptyRow); return resultRows; } // 为JSON列添加前缀,避免列名冲突 foreach (DataColumn col in jsonDt.Columns) { col.ColumnName = string.IsNullOrEmpty(jsonColumnPrefix) ? col.ColumnName : $"{jsonColumnPrefix}_{col.ColumnName}"; } // 遍历JSON行,合并到主行副本中 foreach (DataRow jsonRow in jsonDt.Rows) { var newRow = mainRow.Table.NewRow(); // 复制主行原有数据 mainRow.ItemArray.CopyTo(newRow.ItemArray, 0); // 合并JSON行数据 foreach (DataColumn col in jsonDt.Columns) { if (!newRow.Table.Columns.Contains(col.ColumnName)) { newRow.Table.Columns.Add(col.ColumnName, col.DataType); } newRow[col.ColumnName] = jsonRow[col] ?? DBNull.Value; } resultRows.Add(newRow); } return resultRows; }
2. 处理多JSON列的完整流程
遍历主表每一行,依次处理所有JSON列,逐步合并数据:
public static DataTable MergeAllJsonColumns(DataTable mainTable, List<string> jsonColumnNames) { if (jsonColumnNames == null || !jsonColumnNames.Any()) { return mainTable.Copy(); // 无JSON列,直接返回原表副本 } // 创建结果表结构(复制主表结构) DataTable resultTable = mainTable.Clone(); // 预添加所有JSON列的字段,避免重复添加 foreach (string jsonColName in jsonColumnNames) { string sampleJson = mainTable.AsEnumerable() .FirstOrDefault(r => !string.IsNullOrWhiteSpace(r[jsonColName]?.ToString()))?[jsonColName]?.ToString(); if (!string.IsNullOrWhiteSpace(sampleJson)) { DataTable tempDt = JsonConvert.DeserializeObject<DataTable>(sampleJson); if (tempDt != null) { foreach (DataColumn col in tempDt.Columns) { string newColName = $"{jsonColName}_{col.ColumnName}"; if (!resultTable.Columns.Contains(newColName)) { resultTable.Columns.Add(newColName, col.DataType); } } } } } // 遍历主表行,逐个处理JSON列 foreach (DataRow mainRow in mainTable.Rows) { List<DataRow> currentRows = new List<DataRow> { mainRow }; foreach (string jsonColName in jsonColumnNames) { List<DataRow> tempRows = new List<DataRow>(); foreach (DataRow row in currentRows) { tempRows.AddRange(MergeJsonToRow(row, jsonColName, jsonColName)); } currentRows = tempRows; } // 将合并后的行导入结果表 foreach (DataRow mergedRow in currentRows) { resultTable.ImportRow(mergedRow); } } return resultTable; }
3. 使用示例
假设主表dtable包含Id、InfoJson、DetailJson两个JSON列,调用方式如下:
// 定义所有含JSON的列名 var jsonColumns = new List<string> { "InfoJson", "DetailJson" }; // 执行合并 DataTable mergedTable = MergeAllJsonColumns(dtable, jsonColumns);
关键说明
- 列名冲突处理:通过给JSON列添加原列名前缀(如
InfoJson_Name),避免不同JSON列的同名字段冲突。 - 空JSON处理:若JSON为空或反序列化后无数据,保留原主行数据。
- 行数适配:自动处理JSON是单个对象(单行)或数组(多行)的情况,主行会根据JSON行数自动扩展或直接合并。
内容的提问来源于stack exchange,提问作者SU_Khan
相关产品推荐
相关产品推荐

