使用C#向DataTable插入数据时丢失最后一列的问题
问题描述
从前端通过JavaScript获取到一段JSON字符串,插入DataTable时最后一列(incident列)无法成功插入,现有代码仅能正确处理前4列。
获取到的JSON字符串:
[{"CompanayID":"k123","Role":"Admin","Country":"UK","Asset":"HD"}, {"CompanayID":"k234","Role":"User","Country":"US","Asset":"HD12","incident":"abc 1"}]
使用的C#代码:
DataTable dt = new DataTable("UserDetails"); JavaScriptSerializer serializer = new JavaScriptSerializer(); object[] objCustomers = (object[])serializer.DeserializeObject(customers); var columnNames = ((Dictionary<string, object>)objCustomers[0]).Select(x => x.Key).ToList(); for (int i = 0; i < columnNames.Count; i++) { dt.Columns.Add(columnNames[i]); } for (int i = 0; i < objCustomers.Length; i++) { Dictionary<string, object> keyValue = (Dictionary<string, object>)objCustomers[i]; DataRow dr = dt.NewRow(); foreach (KeyValuePair<string, object> item in keyValue) { for (int k = 0; k < columnNames.Count(); k++) { if (item.Key == columnNames[k].ToString()) { dr[columnNames[k]] = item.Value; break; } } } dt.Rows.Add(dr); }
问题原因
代码仅提取第一个JSON对象的所有键作为DataTable的列名,但第一个对象没有incident字段,导致DataTable从未创建该列。处理第二个JSON对象时,即使存在incident键,也找不到对应的列来插入值。
解决方案
方案1:动态收集所有字段(适合结构不固定的JSON)
遍历所有序列化后的对象,收集所有出现过的键并去重,再基于这些键创建DataTable列,确保不会遗漏任何字段。
修改后的代码:
DataTable dt = new DataTable("UserDetails"); JavaScriptSerializer serializer = new JavaScriptSerializer(); object[] objCustomers = (object[])serializer.DeserializeObject(customers); // 收集所有对象的键,去重 var allColumnNames = new HashSet<string>(); foreach (var obj in objCustomers) { var dict = (Dictionary<string, object>)obj; foreach (var key in dict.Keys) { allColumnNames.Add(key); } } // 创建所有列 foreach (var columnName in allColumnNames) { dt.Columns.Add(columnName); } // 填充数据 foreach (var obj in objCustomers) { var keyValue = (Dictionary<string, object>)obj; DataRow dr = dt.NewRow(); foreach (var item in keyValue) { dr[item.Key] = item.Value; } // 对象没有的字段自动留空(DataRow默认值为DBNull) dt.Rows.Add(dr); }
方案2:使用强类型对象(适合结构固定的JSON)
如果JSON字段结构相对固定,先定义对应类,反序列化成强类型列表后再转换为DataTable,类型更安全且代码更简洁。
首先定义实体类:
public class UserDetail { public string CompanayID { get; set; } public string Role { get; set; } public string Country { get; set; } public string Asset { get; set; } public string incident { get; set; } // 可选字段,允许为null }
转换代码:
JavaScriptSerializer serializer = new JavaScriptSerializer(); List<UserDetail> userList = serializer.Deserialize<List<UserDetail>>(customers); DataTable dt = new DataTable("UserDetails"); // 基于类属性创建列 foreach (var prop in typeof(UserDetail).GetProperties()) { dt.Columns.Add(prop.Name, prop.PropertyType); } // 填充数据 foreach (var user in userList) { DataRow dr = dt.NewRow(); dr["CompanayID"] = user.CompanayID; dr["Role"] = user.Role; dr["Country"] = user.Country; dr["Asset"] = user.Asset; dr["incident"] = user.incident ?? DBNull.Value; // 处理null值 dt.Rows.Add(dr); }
补充说明
- 方案1更灵活,适配JSON字段动态增减的场景;
- 方案2更规范,适合字段结构稳定的场景,便于维护;
- 注意原JSON中
CompanayID存在拼写错误(正确应为CompanyID),可根据需求统一修正。
内容的提问来源于stack exchange,提问作者Jeremy
相关产品推荐
相关产品推荐

