C# DataSet.ReadXml读取XML时重复节点被跳过未存入问题
问题原因
DataSet.ReadXml() 方法会根据XML节点的出现规律自动推断关系型结构:
- 同级下仅出现1次的子节点,会被映射为父级节点对应表的普通列
- 同级下重复出现的同名子节点,不会被当成父表列,而是会被推断为独立的关联子表,通过自动生成的主键/外键和父表关联
你遇到的“节点被跳过”本质是找错了存储位置,重复的ProductionSpecificationText节点值并没有丢失,只是存在自动生成的独立子表中。
验证方法
运行以下代码可以直接查看DataSet生成的所有表,确认数据位置:
DataSet dataSet = new DataSet(); dataSet.ReadXml(@"C:\Users\elhammh\Desktop\xmlfiletest"); // 打印DataSet内所有表的信息 foreach (DataTable table in dataSet.Tables) { Console.WriteLine($"表名:{table.TableName},数据行数:{table.Rows.Count}"); // 打印列名 foreach (DataColumn col in table.Columns) { Console.WriteLine($" 列名:{col.ColumnName}"); } }
执行后你会看到DataSet内共生成2张表:
Production表:共1行数据,存储Number、Code、VehicleID、ModelID、Date这类非重复节点值,同时会自动生成Production_Id这类主键字段用于关联ProductionSpecificationText表:共7行数据,就是你写入的7个重复配置节点值,通过外键字段和Production表关联
自定义读取方案(不拆子表)
如果你不需要关联子表结构,希望把重复节点的值直接合并存入主表,可以先手动定义DataTable结构,再通过LINQ to XML读取填充,避免默认结构推断的拆分逻辑:
DataSet dataSet = new DataSet(); DataTable prodTable = new DataTable("Production"); // 手动定义表结构 prodTable.Columns.Add("Number", typeof(string)); prodTable.Columns.Add("Code", typeof(string)); prodTable.Columns.Add("VehicleID", typeof(string)); prodTable.Columns.Add("ModelID", typeof(string)); prodTable.Columns.Add("Date", typeof(DateTime)); prodTable.Columns.Add("ProductionSpecificationText", typeof(string)); dataSet.Tables.Add(prodTable); // 读取XML手动填充数据 XDocument xDoc = XDocument.Load(@"C:\Users\elhammh\Desktop\xmlfiletest"); // 遍历所有Production节点(单节点/多节点场景都兼容) foreach (XElement prodNode in xDoc.Root.Elements("Production")) { DataRow row = prodTable.NewRow(); row["Number"] = prodNode.Element("Number")?.Value?.Trim(); row["Code"] = prodNode.Element("Code")?.Value?.Trim(); row["VehicleID"] = prodNode.Element("VehicleID")?.Value?.Trim(); row["ModelID"] = prodNode.Element("ModelID")?.Value?.Trim(); if (DateTime.TryParse(prodNode.Element("Date")?.Value, out DateTime prodDate)) { row["Date"] = prodDate; } // 拼接所有重复的ProductionSpecificationText节点值,分隔符可按需替换 var specValues = prodNode.Elements("ProductionSpecificationText") .Select(e => e.Value?.Trim()) .Where(v => !string.IsNullOrEmpty(v)); row["ProductionSpecificationText"] = string.Join(",", specValues); prodTable.Rows.Add(row); }
如果你需要保留多值的结构化存储,直接读取自动生成的
ProductionSpecificationText子表数据即可,不需要额外写解析逻辑,通过表间关联就能拿到对应Production记录下的所有配置值。
内容的提问来源于stack exchange,提问作者Yassin alaoui
相关产品推荐
相关产品推荐

