From da9b5178323df9bb2a2a7bc290babb9b64cdbd37 Mon Sep 17 00:00:00 2001 From: IcedMango <22059332+IcedMango@users.noreply.github.com> Date: Fri, 29 Nov 2024 22:14:30 +0800 Subject: [PATCH] feat: Enhance IDataReader export with DynamicColumnFirst and Custom Formatting Delegate (#700) * Add DynamicColumnFirst in config; * Handle DynamicColumnFirst value assign; Modify DynamicColumns ignore case; * Handle CustomFormatter logic; --- .../Attributes/ExcelColumnAttribute.cs | 2 + src/MiniExcel/IConfiguration.cs | 5 ++ .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 50 +++++++++++++++++-- .../ExcelOpenXmlSheetWriter.DefaultOpenXml.cs | 3 +- .../OpenXml/ExcelOpenXmlSheetWriter.cs | 13 +++++ src/MiniExcel/Utils/CustomPropertyHelper.cs | 2 + 6 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/MiniExcel/Attributes/ExcelColumnAttribute.cs b/src/MiniExcel/Attributes/ExcelColumnAttribute.cs index 9cae6d9b..cbcb519e 100644 --- a/src/MiniExcel/Attributes/ExcelColumnAttribute.cs +++ b/src/MiniExcel/Attributes/ExcelColumnAttribute.cs @@ -57,6 +57,8 @@ public enum ColumnType { Value, Formula } public class DynamicExcelColumn : ExcelColumnAttribute { public string Key { get; set; } + + public Func CustomFormatter { get; set; } public DynamicExcelColumn(string key) { diff --git a/src/MiniExcel/IConfiguration.cs b/src/MiniExcel/IConfiguration.cs index b3580c6d..4faedbc4 100644 --- a/src/MiniExcel/IConfiguration.cs +++ b/src/MiniExcel/IConfiguration.cs @@ -10,5 +10,10 @@ public abstract class Configuration : IConfiguration public DynamicExcelColumn[] DynamicColumns { get; set; } public int BufferSize { get; set; } = 1024 * 512; public bool FastMode { get; set; } = false; + + /// + /// When exporting using DataReader, the data not in DynamicColumn will be filtered. + /// + public bool DynamicColumnFirst { get; set; } = false; } } diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 7df601ec..07b3f73f 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -117,8 +117,25 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr for (var i = 0; i < reader.FieldCount; i++) { var columnName = reader.GetName(i); - var prop = GetColumnInfosFromDynamicConfiguration(columnName); - props.Add(prop); + + if (!_configuration.DynamicColumnFirst) + { + var prop = GetColumnInfosFromDynamicConfiguration(columnName); + props.Add(prop); + continue; + } + + if (_configuration + .DynamicColumns + .Any(a => string.Equals( + a.Key, + columnName, + StringComparison.OrdinalIgnoreCase))) + + { + var prop = GetColumnInfosFromDynamicConfiguration(columnName); + props.Add(prop); + } } maxColumnIndex = props.Count; @@ -149,7 +166,18 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr var xIndex = 1; for (int i = 0; i < fieldCount; i++) { - var cellValue = reader.GetValue(i); + object cellValue; + + if (_configuration.DynamicColumnFirst) + { + var columnIndex = reader.GetOrdinal(props[i].Key.ToString()); + cellValue = reader.GetValue(columnIndex); + } + else + { + cellValue = reader.GetValue(i); + } + await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[i], widths); xIndex++; } @@ -534,7 +562,21 @@ private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowInde var columnType = p.ExcelColumnType; /*Prefix and suffix blank space will lost after SaveAs #294*/ - var preserveSpace = cellValue != null && (cellValue.StartsWith(" ", StringComparison.Ordinal) || cellValue.EndsWith(" ", StringComparison.Ordinal)); + var preserveSpace = cellValue != null && (cellValue.StartsWith(" ", StringComparison.Ordinal) || + cellValue.EndsWith(" ", StringComparison.Ordinal)); + + if (p.CustomFormatter != null) + { + try + { + cellValue = p.CustomFormatter(cellValue); + } + catch (Exception e) + { + //ignored + } + } + await writer.WriteAsync(WorksheetXml.Cell(columnReference, dataType, styleIndex, cellValue, preserveSpace: preserveSpace, columnType: columnType)); widthCollection?.AdjustWidth(cellIndex, cellValue); } diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.DefaultOpenXml.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.DefaultOpenXml.cs index 23bd5731..ccffa8de 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.DefaultOpenXml.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.DefaultOpenXml.cs @@ -192,7 +192,7 @@ private ExcelColumnInfo GetColumnInfosFromDynamicConfiguration(string columnName if (_configuration.DynamicColumns == null || _configuration.DynamicColumns.Length <= 0) return prop; - var dynamicColumn = _configuration.DynamicColumns.SingleOrDefault(_ => _.Key == columnName); + var dynamicColumn = _configuration.DynamicColumns.SingleOrDefault(_ => string.Equals(_.Key , columnName,StringComparison.OrdinalIgnoreCase)); if (dynamicColumn == null || dynamicColumn.Ignore) { return prop; @@ -203,6 +203,7 @@ private ExcelColumnInfo GetColumnInfosFromDynamicConfiguration(string columnName prop.ExcelColumnType = dynamicColumn.Type; prop.ExcelColumnIndex = dynamicColumn.Index; prop.ExcelColumnWidth = dynamicColumn.Width; + prop.CustomFormatter = dynamicColumn.CustomFormatter; //prop.ExcludeNullableType = item2[key]?.GetType(); if (dynamicColumn.Format != null) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs index 4fdfa949..1dea68c0 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs @@ -570,6 +570,19 @@ private void WriteCell(MiniExcelStreamWriter writer, int rowIndex, int cellIndex var styleIndex = tuple.Item1; // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.cell?view=openxml-3.0.1 var dataType = tuple.Item2; // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.cellvalues?view=openxml-3.0.1 var cellValue = tuple.Item3; + + if (columnInfo?.CustomFormatter != null) + { + try + { + cellValue = columnInfo.CustomFormatter(cellValue); + } + catch (Exception e) + { + //ignored + } + } + var columnType = columnInfo?.ExcelColumnType ?? ColumnType.Value; /*Prefix and suffix blank space will lost after SaveAs #294*/ diff --git a/src/MiniExcel/Utils/CustomPropertyHelper.cs b/src/MiniExcel/Utils/CustomPropertyHelper.cs index 0c8d458d..fee4fdef 100644 --- a/src/MiniExcel/Utils/CustomPropertyHelper.cs +++ b/src/MiniExcel/Utils/CustomPropertyHelper.cs @@ -25,6 +25,7 @@ internal class ExcelColumnInfo public bool ExcelIgnore { get; internal set; } public int ExcelFormatId { get; internal set; } public ColumnType ExcelColumnType { get; internal set; } + public Func CustomFormatter { get; set; } } internal class ExcellSheetInfo @@ -310,6 +311,7 @@ internal static void SetDictionaryColumnInfo(List _props, objec isIgnore = dynamicColumn.Ignore; p.ExcelColumnWidth = dynamicColumn.Width; p.ExcelColumnType = dynamicColumn.Type; + p.CustomFormatter = dynamicColumn.CustomFormatter; } } if (!isIgnore)