使用OpenXML SDK将DataSet导出为Excel时遇数据填充难题
问题解决:用OpenXML SDK将DataSet导出为多工作表Excel
先理清Sheet与Worksheet的核心区别
- Sheet:属于工作簿级别的元数据条目,仅用于声明工作表的名称、唯一标识(SheetId)以及指向实际内容的关联ID(Id),本身不存储任何单元格数据。
- WorksheetPart:是存储工作表实际内容的部件,包含
SheetData(行、单元格集合)、格式设置等核心数据。每个Sheet必须关联一个独立的WorksheetPart,你之前的错误是所有Sheet都指向同一个WorksheetPart,导致文件结构异常。
修正后的完整代码
private byte[] DataSetToXlsx(DataSet ds) { using var stream = new MemoryStream(); using var spreadsheet = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook); // 创建工作簿部件 var workbookPart = spreadsheet.AddWorkbookPart(); workbookPart.Workbook = new Workbook(); var sheets = workbookPart.Workbook.AppendChild(new Sheets()); foreach (DataTable dt in ds.Tables) { // 为每个DataTable创建独立的WorksheetPart var worksheetPart = workbookPart.AddNewPart<WorksheetPart>(); var sheetData = new SheetData(); worksheetPart.Worksheet = new Worksheet(sheetData); // 1. 写入表头行 var headerRow = new Row(); foreach (DataColumn col in dt.Columns) { headerRow.AppendChild(CreateCell(col.ColumnName, CellValues.String)); } sheetData.AppendChild(headerRow); // 2. 写入数据行 foreach (DataRow row in dt.Rows) { var dataRow = new Row(); foreach (var item in row.ItemArray) { var cellValue = item == DBNull.Value ? string.Empty : item.ToString(); // 根据数据类型设置单元格类型,可按需扩展更多类型判断 var cellType = item is int || item is double || item is decimal ? CellValues.Number : CellValues.String; dataRow.AppendChild(CreateCell(cellValue, cellType)); } sheetData.AppendChild(dataRow); } // 创建Sheet元数据,关联当前WorksheetPart var sheetName = string.IsNullOrWhiteSpace(dt.TableName) ? $"Sheet {sheets.Count() + 1}" : dt.TableName; var sheet = new Sheet { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = (uint)(sheets.Count() + 1), Name = sheetName }; sheets.Append(sheet); } workbookPart.Workbook.Save(); stream.Seek(0, SeekOrigin.Begin); return stream.ToArray(); } // 辅助方法:创建带值和类型的单元格 private Cell CreateCell(string cellValue, CellValues cellType) { return new Cell { CellValue = new CellValue(cellValue), DataType = new EnumValue<CellValues>(cellType) }; }
关键修正点说明
- 每个DataTable对应独立WorksheetPart:循环内每次创建新的WorksheetPart,确保每个工作表拥有独立的内容容器,避免所有Sheet共享同一内容导致的结构错误。
- 填充SheetData内容:通过
SheetData对象依次添加表头行和数据行,为每个单元格明确设置值和数据类型,确保Excel能正常解析文件。 - 正确绑定Sheet与WorksheetPart:每个Sheet的
Id属性指向当前循环生成的WorksheetPart的唯一ID,完成元数据与实际内容的关联。
内容的提问来源于stack exchange,提问作者Stephan G
相关产品推荐
相关产品推荐

