Skip to content

Commit 03ce5b7

Browse files
committed
- [Bug] Fiexd Query multiple same title will cause startcell to get wrong column index #I4YCLQ
- [OPT] Optimize Query<T> algorithm
1 parent c5108d3 commit 03ce5b7

13 files changed

+125
-199
lines changed

docs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222

2323
---
2424

25+
### 1.24.2
26+
- [Bug] Fiexd Query multiple same title will cause startcell to get wrong column index #I4YCLQ
27+
- [OPT] Optimize Query<T> algorithm
28+
2529
### 1.24.1
2630
- [Bug] Fiexd QueryAsync configulation not working #338
2731
- [Bug] Fixed QueryAsync not return dynamic type

docs/README.zh-CN.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
---
3434

35+
### 1.24.2
36+
- [Bug] Query 有多个相同标题会导致StartCell无法正确取得该栏位 #I4YCLQ
37+
- [OPT] 优化 Query<T> 的算法
38+
3539
### 1.24.1
3640
- [Bug] 修正 QueryAsync configulation 没有效果问题 #338
3741
- [Bug] 修正 QueryAsync 无法使用 dynamic 类别

docs/README.zh-Hant.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
---
2626

27+
### 1.24.2
28+
- [Bug] Query<T> 有多個相同標題會導致StartCell無法正確取得該欄位 #I4YCLQ
29+
- [OPT] 優化 Query<T> 的算法
2730

2831
### 1.24.1
2932
- [Bug] 修正 QueryAsync configulation 沒有效果問題 #338

samples/xlsx/TestIssueI4YCLQ.xlsx

9.22 MB
Binary file not shown.

samples/xlsx/TestIssueI4YCLQ_2.xlsx

9.77 KB
Binary file not shown.

src/MiniExcel/Attributes/ExcelColumnIndexAttribute.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,22 @@
77
public class ExcelColumnIndexAttribute : Attribute
88
{
99
public int ExcelColumnIndex { get; set; }
10+
internal string ExcelXName { get; set; }
1011
public ExcelColumnIndexAttribute(string columnName) => Init(ColumnHelper
11-
.GetColumnIndex(columnName));
12+
.GetColumnIndex(columnName), columnName);
1213
public ExcelColumnIndexAttribute(int columnIndex) => Init(columnIndex);
1314

14-
private void Init(int columnIndex)
15+
private void Init(int columnIndex,string columnName=null)
1516
{
1617
if (columnIndex < 0)
1718
{
1819
throw new ArgumentOutOfRangeException(nameof(columnIndex), columnIndex, $"Column index {columnIndex} must be greater or equal to zero.");
1920
}
21+
if (ExcelXName == null)
22+
if(columnName != null)
23+
ExcelXName = columnName;
24+
else
25+
ExcelXName = ColumnHelper.GetAlphabetColumnName(columnIndex);
2026
ExcelColumnIndex = columnIndex;
2127
}
2228
}

src/MiniExcel/Csv/CsvReader.cs

Lines changed: 3 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using MiniExcelLibs.Utils;
1+
using MiniExcelLibs.OpenXml;
2+
using MiniExcelLibs.Utils;
23
using System;
34
using System.Collections.Generic;
45
using System.Data;
@@ -64,65 +65,9 @@ public IEnumerable<IDictionary<string, object>> Query(bool useHeaderRow, string
6465
}
6566
}
6667
}
67-
6868
public IEnumerable<T> Query<T>(string sheetName, string startCell) where T : class, new()
6969
{
70-
var type = typeof(T);
71-
72-
Dictionary<int, ExcelCustomPropertyInfo> idxProps = new Dictionary<int, ExcelCustomPropertyInfo>();
73-
using (var reader = _config.StreamReaderFunc(_stream))
74-
{
75-
var row = string.Empty;
76-
string[] read;
77-
78-
//header
79-
{
80-
row = reader.ReadLine();
81-
read = Split(row);
82-
83-
var props = CustomPropertyHelper.GetExcelCustomPropertyInfos(type, read);
84-
var index = 0;
85-
foreach (var v in read)
86-
{
87-
var p = props.SingleOrDefault(w => w.ExcelColumnName == v);
88-
if (p != null)
89-
idxProps.Add(index, p);
90-
index++;
91-
}
92-
}
93-
{
94-
while ((row = reader.ReadLine()) != null)
95-
{
96-
read = Split(row);
97-
98-
//body
99-
{
100-
var v = new T();
101-
102-
var rowIndex = 0; //TODO: rowindex = startcell rowindex
103-
foreach (var p in idxProps)
104-
{
105-
var pInfo = p.Value;
106-
107-
{
108-
109-
object newV = null;
110-
object itemValue = read[p.Key];
111-
112-
if (itemValue == null)
113-
continue;
114-
115-
newV = TypeHelper.TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell,_config);
116-
}
117-
}
118-
119-
rowIndex++;
120-
yield return v;
121-
}
122-
}
123-
124-
}
125-
}
70+
return ExcelOpenXmlSheetReader.QueryImpl<T>(Query(false, sheetName, startCell), startCell, this._config);
12671
}
12772

12873
private string[] Split(string row)

src/MiniExcel/IExcelReader.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using System.Collections.Generic;
1+
using MiniExcelLibs.Utils;
2+
using System.Collections.Generic;
23
using System.Data;
34
using System.IO;
5+
using System.Linq;
46
using System.Threading.Tasks;
57

68
namespace MiniExcelLibs

src/MiniExcel/MiniExcelDynamic.cs

Lines changed: 0 additions & 111 deletions
This file was deleted.

src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -400,21 +400,45 @@ private void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, ref Di
400400
}
401401

402402
public IEnumerable<T> Query<T>(string sheetName, string startCell) where T : class, new()
403+
{
404+
return ExcelOpenXmlSheetReader.QueryImpl<T>(Query(false, sheetName, startCell), startCell, this._config);
405+
}
406+
407+
public static IEnumerable<T> QueryImpl<T>(IEnumerable<IDictionary<string, object>> values, string startCell, Configuration configuration) where T : class, new()
403408
{
404409
var type = typeof(T);
405410

406411
List<ExcelCustomPropertyInfo> props = null;
407-
var headers = Query(false, sheetName, startCell).FirstOrDefault()?.Values?.Select(s => s?.ToString())?.ToArray(); //TODO:need to optimize
412+
//TODO:need to optimize
408413

414+
string[] headers = null;
415+
416+
Dictionary<string, int> headersDic = null;
417+
string[] keys = null;
409418
var first = true;
410419
var rowIndex = 0;
411-
foreach (var item in Query(true, sheetName, startCell))
420+
foreach (var item in values)
412421
{
422+
413423
if (first)
414424
{
425+
keys = item.Keys.ToArray();//.Select((s, i) => new { s,i}).ToDictionary(_=>_.s,_=>_.i);
426+
headers = item?.Values?.Select(s => s?.ToString())?.ToArray(); //TODO:remove
427+
headersDic = headers.Select((o, i) => new { o=(o == null ? "" : o), i } )
428+
.OrderBy(x => x.i)
429+
.GroupBy(x => x.o)
430+
.Select(group => new { Group = group, Count = group.Count() })
431+
.SelectMany(groupWithCount =>
432+
groupWithCount.Group.Select(b => b)
433+
.Zip(
434+
Enumerable.Range(1, groupWithCount.Count),
435+
(j, i) => new { key = (i == 1 ? j.o : $"{j.o}_____{i}"), idx = j.i, RowNumber = i }
436+
)
437+
).ToDictionary(_ => _.key, _ => _.idx);
415438
//TODO: alert don't duplicate column name
416-
props = CustomPropertyHelper.GetExcelCustomPropertyInfos(type, headers);
439+
props = CustomPropertyHelper.GetExcelCustomPropertyInfos(type, keys);
417440
first = false;
441+
continue;
418442
}
419443
var v = new T();
420444
foreach (var pInfo in props)
@@ -423,29 +447,33 @@ private void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, ref Di
423447
{
424448
foreach (var alias in pInfo.ExcelColumnAliases)
425449
{
426-
if (item.ContainsKey(alias))
450+
if (headersDic.ContainsKey(alias))
427451
{
428452
object newV = null;
429-
object itemValue = item[alias];
453+
object itemValue = item[keys[headersDic[alias]]];
430454

431455
if (itemValue == null)
432456
continue;
433457

434-
newV = TypeHelper.TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell, _config);
458+
newV = TypeHelper.TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell, configuration);
435459
}
436460
}
437461
}
438462

463+
439464
//Q: Why need to check every time? A: it needs to check everytime, because it's dictionary
440-
if (item.ContainsKey(pInfo.ExcelColumnName))
441465
{
442466
object newV = null;
443-
object itemValue = item[pInfo.ExcelColumnName];
467+
object itemValue = null;
468+
if (pInfo.ExcelXName != null && keys.Contains(pInfo.ExcelXName))
469+
itemValue = item[pInfo.ExcelXName];
470+
else if (headersDic.ContainsKey(pInfo.ExcelColumnName))
471+
itemValue = item[keys[headersDic[pInfo.ExcelColumnName]]];
444472

445473
if (itemValue == null)
446474
continue;
447475

448-
newV = TypeHelper.TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell, _config);
476+
newV = TypeHelper.TypeMapping(v, pInfo, newV, itemValue, rowIndex, startCell, configuration);
449477
}
450478
}
451479
rowIndex++;

0 commit comments

Comments
 (0)