Skip to content

Commit a5c3e88

Browse files
Merge pull request #786: Fixing issue 584
Fixed bug that made the DynamicExcelColumn property "Ignore" not work when generating using an IDataReader as source
2 parents 6744a78 + 34ded1a commit a5c3e88

File tree

6 files changed

+155
-104
lines changed

6 files changed

+155
-104
lines changed

src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public int[] SaveAs()
6262

6363
GenerateEndXml();
6464
_archive.Dispose();
65-
65+
6666
return rowsWritten.ToArray();
6767
}
6868

@@ -193,22 +193,23 @@ private int WriteValues(MiniExcelStreamWriter writer, object values)
193193
WriteEmptySheet(writer);
194194
return 0;
195195
}
196-
var maxColumnIndex = props.Count;
196+
197197
int maxRowIndex;
198+
var maxColumnIndex = props.Count(x => x != null && !x.ExcelIgnore);
198199

199200
writer.Write(WorksheetXml.StartWorksheetWithRelationship);
200201

201202
long dimensionPlaceholderPostition = 0;
202203

203204
// We can write the dimensions directly if the row count is known
204-
if (_configuration.FastMode && !isKnownCount)
205+
if (isKnownCount)
205206
{
206-
dimensionPlaceholderPostition = WriteDimensionPlaceholder(writer);
207+
maxRowIndex = _printHeader ? count + 1 : count;
208+
writer.Write(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, maxColumnIndex)));
207209
}
208-
else if (isKnownCount)
210+
else if (_configuration.FastMode)
209211
{
210-
maxRowIndex = count + (_printHeader ? 1 : 0);
211-
writer.Write(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, props.Count)));
212+
dimensionPlaceholderPostition = WriteDimensionPlaceholder(writer);
212213
}
213214

214215
//sheet view
@@ -219,7 +220,7 @@ private int WriteValues(MiniExcelStreamWriter writer, object values)
219220
long columnWidthsPlaceholderPosition = 0;
220221
if (_configuration.EnableAutoWidth)
221222
{
222-
columnWidthsPlaceholderPosition = WriteColumnWidthPlaceholders(writer, props);
223+
columnWidthsPlaceholderPosition = WriteColumnWidthPlaceholders(writer, maxColumnIndex);
223224
widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props);
224225
}
225226
else
@@ -263,21 +264,23 @@ private int WriteValues(MiniExcelStreamWriter writer, object values)
263264
}
264265
if (_configuration.EnableAutoWidth)
265266
{
266-
OverWriteColumnWidthPlaceholders(writer, columnWidthsPlaceholderPosition, widths?.Columns);
267+
OverwriteColumnWidthPlaceholders(writer, columnWidthsPlaceholderPosition, widths?.Columns);
267268
}
268269

269-
var toSubtract = _printHeader ? 1 : 0;
270-
return maxRowIndex - toSubtract;
270+
if (_printHeader)
271+
maxRowIndex--;
272+
273+
return maxRowIndex;
271274
}
272275

273-
private static long WriteColumnWidthPlaceholders(MiniExcelStreamWriter writer, ICollection<ExcelColumnInfo> props)
276+
private static long WriteColumnWidthPlaceholders(MiniExcelStreamWriter writer, int count)
274277
{
275278
var placeholderPosition = writer.Flush();
276-
writer.WriteWhitespace(WorksheetXml.GetColumnPlaceholderLength(props.Count));
279+
writer.WriteWhitespace(WorksheetXml.GetColumnPlaceholderLength(count));
277280
return placeholderPosition;
278281
}
279282

280-
private static void OverWriteColumnWidthPlaceholders(MiniExcelStreamWriter writer, long placeholderPosition, IEnumerable<ExcelColumnWidth> columnWidths)
283+
private static void OverwriteColumnWidthPlaceholders(MiniExcelStreamWriter writer, long placeholderPosition, IEnumerable<ExcelColumnWidth> columnWidths)
281284
{
282285
var position = writer.Flush();
283286

@@ -300,29 +303,30 @@ private static void WriteColumnsWidths(MiniExcelStreamWriter writer, IEnumerable
300303
}
301304
writer.Write(WorksheetXml.Column(column.Index, column.Width));
302305
}
303-
if (!hasWrittenStart)
306+
307+
if (hasWrittenStart)
304308
{
305-
return;
309+
writer.Write(WorksheetXml.EndCols);
306310
}
307-
writer.Write(WorksheetXml.EndCols);
308311
}
309312

310313
private void PrintHeader(MiniExcelStreamWriter writer, List<ExcelColumnInfo> props)
311314
{
312-
var xIndex = 1;
313-
var yIndex = 1;
315+
const int yIndex = 1;
314316
writer.Write(WorksheetXml.StartRow(yIndex));
315317

318+
var xIndex = 1;
316319
foreach (var p in props)
317320
{
318-
if (p == null)
321+
//reason : https://github.com/mini-software/MiniExcel/issues/142
322+
if (p != null)
319323
{
320-
xIndex++; //reason : https://github.com/mini-software/MiniExcel/issues/142
321-
continue;
324+
if (p.ExcelIgnore)
325+
continue;
326+
327+
var r = ExcelOpenXmlUtils.ConvertXyToCell(xIndex, yIndex);
328+
WriteCell(writer, r, columnName: p.ExcelColumnName);
322329
}
323-
324-
var r = ExcelOpenXmlUtils.ConvertXyToCell(xIndex, yIndex);
325-
WriteCell(writer, r, columnName: p.ExcelColumnName);
326330
xIndex++;
327331
}
328332

src/MiniExcel/OpenXml/ExcelWidthCollection.cs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,21 @@ public sealed class ExcelColumnWidth
1010
public int Index { get; set; }
1111
public double Width { get; set; }
1212

13-
internal static IEnumerable<ExcelColumnWidth> FromProps(IEnumerable<ExcelColumnInfo> props, double? minWidth = null)
13+
internal static IEnumerable<ExcelColumnWidth> FromProps(ICollection<ExcelColumnInfo> props, double? minWidth = null)
1414
{
1515
var i = 1;
1616
foreach (var p in props)
1717
{
18-
if (p == null || (p.ExcelColumnWidth == null && minWidth == null))
18+
if (p?.ExcelColumnWidth != null || minWidth != null)
1919
{
20-
i++;
21-
continue;
20+
var colIndex = p?.ExcelColumnIndex + 1;
21+
yield return new ExcelColumnWidth
22+
{
23+
Index = colIndex ?? i,
24+
Width = p?.ExcelColumnWidth ?? minWidth.Value
25+
};
2226
}
23-
var colIndex = p.ExcelColumnIndex == null ? i : p.ExcelColumnIndex.GetValueOrDefault() + 1;
24-
yield return new ExcelColumnWidth
25-
{
26-
Index = colIndex,
27-
Width = p.ExcelColumnWidth ?? minWidth.Value,
28-
};
27+
2928
i++;
3029
}
3130
}
@@ -38,21 +37,20 @@ public sealed class ExcelWidthCollection
3837

3938
public IEnumerable<ExcelColumnWidth> Columns => _columnWidths.Values;
4039

41-
internal ExcelWidthCollection(double minWidth, double maxWidth, IEnumerable<ExcelColumnInfo> props)
40+
internal ExcelWidthCollection(double minWidth, double maxWidth, ICollection<ExcelColumnInfo> props)
4241
{
4342
_maxWidth = maxWidth;
4443
_columnWidths = ExcelColumnWidth.FromProps(props, minWidth).ToDictionary(x => x.Index);
4544
}
4645

4746
public void AdjustWidth(int columnIndex, string columnValue)
4847
{
49-
if (string.IsNullOrEmpty(columnValue) || !_columnWidths.TryGetValue(columnIndex, out var currentWidth))
48+
if (!string.IsNullOrEmpty(columnValue)
49+
&& _columnWidths.TryGetValue(columnIndex, out var currentWidth))
5050
{
51-
return;
51+
var adjustedWidth = Math.Max(currentWidth.Width, GetApproximateTextWidth(columnValue.Length));
52+
currentWidth.Width = Math.Min(_maxWidth, adjustedWidth);
5253
}
53-
54-
var adjustedWidth = Math.Max(currentWidth.Width, GetApproximateRequiredCalibriWidth(columnValue.Length));
55-
currentWidth.Width = Math.Min(_maxWidth, adjustedWidth);
5654
}
5755

5856
/// <summary>
@@ -61,13 +59,12 @@ public void AdjustWidth(int columnIndex, string columnValue)
6159
/// <remarks>
6260
/// Rounds the result to 2 decimal places.
6361
/// </remarks>
64-
public static double GetApproximateRequiredCalibriWidth(int textLength)
62+
public static double GetApproximateTextWidth(int textLength)
6563
{
66-
double characterWidthFactor = 1.2; // Estimated factor for Calibri, 11pt
67-
double padding = 2; // Add some padding for extra spacing
68-
69-
double excelColumnWidth = (textLength * characterWidthFactor) + padding;
64+
const double characterWidthFactor = 1.2; // Estimated factor for Calibri, 11pt
65+
const double padding = 2; // Add some padding for extra spacing
7066

67+
var excelColumnWidth = (textLength * characterWidthFactor) + padding;
7168
return Math.Round(excelColumnWidth, 2);
7269
}
7370
}

src/MiniExcel/Utils/CustomPropertyHelper.cs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ internal static List<ExcelColumnInfo> SortCustomProps(List<ExcelColumnInfo> prop
121121

122122
internal static List<ExcelColumnInfo> GetExcelCustomPropertyInfos(Type type, string[] keys, Configuration configuration)
123123
{
124-
var flags = BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance;
124+
const BindingFlags flags = BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance;
125125
var props = GetExcelPropertyInfo(type, flags, configuration)
126126
.Where(prop => prop.Property.Info.GetSetMethod() != null // why not .Property.CanWrite? because it will use private setter
127127
&& !prop.Property.Info.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore)
@@ -154,9 +154,9 @@ internal static string DescriptionAttr(Type type, object source)
154154
{
155155
var name = source?.ToString();
156156
return type
157-
.GetField(name)? //For some database dirty data, there may be no way to change to the correct enumeration, will return NULL
158-
.GetCustomAttribute<DescriptionAttribute>(false)?
159-
.Description
157+
.GetField(name) //For some database dirty data, there may be no way to change to the correct enumeration, will return NULL
158+
?.GetCustomAttribute<DescriptionAttribute>(false)
159+
?.Description
160160
?? name;
161161
}
162162

@@ -243,8 +243,10 @@ internal static ExcellSheetInfo GetExcellSheetInfo(Type type, Configuration conf
243243
internal static List<ExcelColumnInfo> GetDictionaryColumnInfo(IDictionary<string, object> dicString, IDictionary dic, Configuration configuration)
244244
{
245245
var props = new List<ExcelColumnInfo>();
246-
var keys = dicString?.Keys.ToList() ?? dic?.Keys
247-
?? throw new NotSupportedException();
246+
247+
var keys = dicString?.Keys.ToList()
248+
?? dic?.Keys
249+
?? throw new NotSupportedException();
248250

249251
foreach (var key in keys)
250252
{
@@ -261,9 +263,7 @@ internal static void SetDictionaryColumnInfo(List<ExcelColumnInfo> props, object
261263
ExcelColumnName = key?.ToString()
262264
};
263265

264-
// TODO:Dictionary value type is not fiexed
265-
//var _t =
266-
//var gt = Nullable.GetUnderlyingType(p.PropertyType);
266+
// TODO:Dictionary value type is not fixed
267267
var isIgnore = false;
268268
if (configuration.DynamicColumns != null && configuration.DynamicColumns.Length > 0)
269269
{
@@ -328,9 +328,10 @@ internal static List<ExcelColumnInfo> GetColumnInfoFromValue(object value, Confi
328328
}
329329
}
330330

331-
private static bool ValueIsNeededToDetermineProperties(Type type) => type == typeof(object)
332-
|| typeof(IDictionary<string, object>).IsAssignableFrom(type)
333-
|| typeof(IDictionary).IsAssignableFrom(type);
331+
private static bool ValueIsNeededToDetermineProperties(Type type) =>
332+
typeof(object) == type ||
333+
typeof(IDictionary<string, object>).IsAssignableFrom(type) ||
334+
typeof(IDictionary).IsAssignableFrom(type);
334335

335336
internal static ExcelColumnInfo GetColumnInfosFromDynamicConfiguration(string columnName, Configuration configuration)
336337
{
@@ -346,16 +347,20 @@ internal static ExcelColumnInfo GetColumnInfosFromDynamicConfiguration(string co
346347
var dynamicColumn = configuration.DynamicColumns
347348
.SingleOrDefault(col => string.Equals(col.Key, columnName, StringComparison.OrdinalIgnoreCase));
348349

349-
if (dynamicColumn == null || dynamicColumn.Ignore)
350+
if (dynamicColumn == null)
350351
return prop;
351352

352353
prop.Nullable = true;
353354
prop.ExcelIgnore = dynamicColumn.Ignore;
354355
prop.ExcelColumnType = dynamicColumn.Type;
355-
prop.ExcelColumnIndex = dynamicColumn.Index;
356356
prop.ExcelColumnWidth = dynamicColumn.Width;
357357
prop.CustomFormatter = dynamicColumn.CustomFormatter;
358358

359+
if (dynamicColumn.Index > -1)
360+
{
361+
prop.ExcelColumnIndex = dynamicColumn.Index;
362+
}
363+
359364
if (dynamicColumn.Format != null)
360365
{
361366
prop.ExcelFormat = dynamicColumn.Format;

src/MiniExcel/WriteAdapter/DataReaderWriteAdapter.cs

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,8 @@ public List<ExcelColumnInfo> GetColumns()
3030
for (var i = 0; i < _reader.FieldCount; i++)
3131
{
3232
var columnName = _reader.GetName(i);
33-
34-
if (!_configuration.DynamicColumnFirst)
35-
{
36-
var prop = CustomPropertyHelper.GetColumnInfosFromDynamicConfiguration(columnName, _configuration);
37-
props.Add(prop);
38-
continue;
39-
}
40-
41-
if (_configuration
42-
.DynamicColumns
43-
.Any(a => string.Equals(
44-
a.Key,
45-
columnName,
46-
StringComparison.OrdinalIgnoreCase)))
47-
33+
if (!_configuration.DynamicColumnFirst ||
34+
_configuration.DynamicColumns.Any(d => string.Equals(d.Key, columnName, StringComparison.OrdinalIgnoreCase)))
4835
{
4936
var prop = CustomPropertyHelper.GetColumnInfosFromDynamicConfiguration(columnName, _configuration);
5037
props.Add(prop);
@@ -64,16 +51,17 @@ public IEnumerable<IEnumerable<CellWriteInfo>> GetRows(List<ExcelColumnInfo> pro
6451

6552
private IEnumerable<CellWriteInfo> GetRowValues(List<ExcelColumnInfo> props)
6653
{
67-
for (int i = 0, column = 1; i < _reader.FieldCount; i++, column++)
54+
var column = 1;
55+
for (int i = 0; i < _reader.FieldCount; i++)
6856
{
69-
if (_configuration.DynamicColumnFirst)
70-
{
71-
var columnIndex = _reader.GetOrdinal(props[i].Key.ToString());
72-
yield return new CellWriteInfo(_reader.GetValue(columnIndex), column, props[i]);
73-
}
74-
else
57+
var prop = props[i];
58+
if (prop != null && !prop.ExcelIgnore)
7559
{
76-
yield return new CellWriteInfo(_reader.GetValue(i), column, props[i]);
60+
var columnIndex = _configuration.DynamicColumnFirst
61+
? _reader.GetOrdinal(prop.Key.ToString()) : i;
62+
63+
yield return new CellWriteInfo(_reader.GetValue(columnIndex), column, prop);
64+
column++;
7765
}
7866
}
7967
}

tests/MiniExcelTests/MiniExcelAutoAdjustWidthTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ private static void AssertExpectedWidth(string path, OpenXmlConfiguration config
154154
{
155155
var expectedWidth = column.Min.Value switch
156156
{
157-
1 => ExcelWidthCollection.GetApproximateRequiredCalibriWidth(AutoAdjustTestParameters.column1MaxStringLength),
158-
2 => ExcelWidthCollection.GetApproximateRequiredCalibriWidth(AutoAdjustTestParameters.column2MaxStringLength),
157+
1 => ExcelWidthCollection.GetApproximateTextWidth(AutoAdjustTestParameters.column1MaxStringLength),
158+
2 => ExcelWidthCollection.GetApproximateTextWidth(AutoAdjustTestParameters.column2MaxStringLength),
159159
3 => configuration.MinWidth,
160160
4 => configuration.MaxWidth,
161161
_ => throw new Exception("Unexpected column"),
@@ -198,8 +198,8 @@ public static List<Dictionary<string, object>> GetDictionaryTestData() => GetTes
198198
{
199199
EnableAutoWidth = true,
200200
FastMode = true,
201-
MinWidth = ExcelWidthCollection.GetApproximateRequiredCalibriWidth(minStringLength),
202-
MaxWidth = ExcelWidthCollection.GetApproximateRequiredCalibriWidth(maxStringLength)
201+
MinWidth = ExcelWidthCollection.GetApproximateTextWidth(minStringLength),
202+
MaxWidth = ExcelWidthCollection.GetApproximateTextWidth(maxStringLength)
203203
};
204204
}
205205
}

0 commit comments

Comments
 (0)