SaveAsByTemplate support input IEnmerable<IDicionary<string,object>> or DapperRows or DataTable parameters

This commit is contained in:
ITWeiHan 2021-04-18 12:39:40 +08:00
parent fbfca6354e
commit ff746cf928
5 changed files with 226 additions and 11 deletions

View File

@ -8,7 +8,7 @@
### 0.13.1
- [New] SaveAsByTemplate by template bytes, convenient to cache and support multiple users to read the same template at the same time #189
- [New] SaveAsByTemplate support input `IEnmerable<IDicionary<string,object>> or DapperRows` parameters [#201](https://github.com/shps951023/MiniExcel/issues/201)
- [New] SaveAsByTemplate support input `IEnmerable<IDicionary<string,object>> or DapperRows or DataTable` parameters [#201](https://github.com/shps951023/MiniExcel/issues/201)
- [Bug] Fix after stream SaveAs/SaveAsByTemplate, miniexcel will close stream [#200](https://github.com/shps951023/MiniExcel/issues/200)
### 0.13.0

View File

@ -9,7 +9,7 @@
### 0.13.1
- [New] SaveAsByTemplate 支持读取模板 byte[],方便缓存跟支持多用户同时读取同一个模板 #189
- [New] SaveAsByTemplate 支持传入 `IEnmerable<IDicionary<string,object>> 或 DapperRows` 参数 [#201](https://github.com/shps951023/MiniExcel/issues/201)
- [New] SaveAsByTemplate 支持传入 `IEnmerable<IDicionary<string,object>> 或 DapperRows 或 DataTable` 参数 [#201](https://github.com/shps951023/MiniExcel/issues/201)
- [Bug] 修正使用 stream SaveAs/SaveAsByTemplate 系统会自动关闭流 stream [#200](https://github.com/shps951023/MiniExcel/issues/200)
### 0.13.0

View File

@ -9,7 +9,7 @@
### 0.13.1
- [New] SaveAsByTemplate 支持讀取模板 byte[],方便緩存跟支持多用戶同時讀取同一個模板 [#189](https://github.com/shps951023/MiniExcel/issues/189)
- [New] SaveAsByTemplate 支持傳入 `IEnmerable<IDicionary<string,object>> 或 DapperRows` 參數 [#201](https://github.com/shps951023/MiniExcel/issues/201)
- [New] SaveAsByTemplate 支持傳入 `IEnmerable<IDicionary<string,object>> 或 DapperRows 或 DataTable` 參數 [#201](https://github.com/shps951023/MiniExcel/issues/201)
- [Bug] 修正使用 stream SaveAs/SaveAsByTemplate 系統會自動關閉流 stream [#200](https://github.com/shps951023/MiniExcel/issues/200)
### 0.13.0

View File

@ -3,6 +3,7 @@ using MiniExcelLibs.Zip;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.IO.Compression;
using System.Linq;
@ -21,8 +22,9 @@ namespace MiniExcelLibs.OpenXml
public string IEnumerablePropName { get; set; }
public XmlElement Row { get; set; }
public Type IEnumerableGenricType { get; set; }
public IDictionary<string, PropInfo > PropsMap { get; set; }
public IDictionary<string, PropInfo> PropsMap { get; set; }
public bool IsDictionary { get; set; }
public bool IsDataTable { get; set; }
public IEnumerable CellIEnumerableValues { get; set; }
}
@ -75,12 +77,11 @@ namespace MiniExcelLibs.OpenXml
//TODO: some xlsx without r
originRowIndex = int.Parse(row.GetAttribute("r"));
var newRowIndex = originRowIndex + rowIndexDiff;
if (xInfo.CellIEnumerableValues != null)
{
var first = true;
foreach (var item in xInfo.CellIEnumerableValues)
{
var newRow = row.Clone() as XmlElement;
@ -107,6 +108,42 @@ namespace MiniExcelLibs.OpenXml
}
var cellValueStr = ExcelOpenXmlUtils.EncodeXML(cellValue);
var type = propInfo.Value.UnderlyingTypePropType;
if (type == typeof(bool))
{
cellValueStr = (bool)cellValue ? "1" : "0";
}
else if (type == typeof(DateTime))
{
//c.SetAttribute("t", "d");
cellValueStr = ((DateTime)cellValue).ToString("yyyy-MM-dd HH:mm:ss");
}
//TODO: ![image](https://user-images.githubusercontent.com/12729184/114848248-17735880-9e11-11eb-8258-63266bda0a1a.png)
newRow.InnerXml = newRow.InnerXml.Replace(key, cellValueStr);
}
}
else if (xInfo.IsDataTable)
{
var datarow = item as DataRow;
foreach (var propInfo in xInfo.PropsMap)
{
var key = $"{{{{{xInfo.IEnumerablePropName}.{propInfo.Key}}}}}";
if (item == null) //![image](https://user-images.githubusercontent.com/12729184/114728510-bc3e5900-9d71-11eb-9721-8a414dca21a0.png)
{
newRow.InnerXml = newRow.InnerXml.Replace(key, "");
continue;
}
var cellValue = datarow[propInfo.Key];
if (cellValue == null)
{
newRow.InnerXml = newRow.InnerXml.Replace(key, "");
continue;
}
var cellValueStr = ExcelOpenXmlUtils.EncodeXML(cellValue);
var type = propInfo.Value.UnderlyingTypePropType;
if (type == typeof(bool))
@ -279,9 +316,9 @@ namespace MiniExcelLibs.OpenXml
{
xRowInfo.IsDictionary = true;
var dic = element as IDictionary<string, object>;
xRowInfo.PropsMap = dic.Keys.ToDictionary(key => key, key => dic[key] != null
? new PropInfo { UnderlyingTypePropType= Nullable.GetUnderlyingType(dic[key].GetType()) ?? dic[key].GetType() }
: new PropInfo { UnderlyingTypePropType = typeof(object) } ) ;
xRowInfo.PropsMap = dic.Keys.ToDictionary(key => key, key => dic[key] != null
? new PropInfo { UnderlyingTypePropType = Nullable.GetUnderlyingType(dic[key].GetType()) ?? dic[key].GetType() }
: new PropInfo { UnderlyingTypePropType = typeof(object) });
}
else
{
@ -296,14 +333,13 @@ namespace MiniExcelLibs.OpenXml
}
}
//TODO: check if not contain 1 index
//only check first one match IEnumerable, so only render one collection at same row
// auto check type https://github.com/shps951023/MiniExcel/issues/177
var prop = xRowInfo.PropsMap[propNames[1]];
var type = prop.UnderlyingTypePropType; //avoid nullable
//
//
if (!xRowInfo.PropsMap.ContainsKey(propNames[1]))
throw new InvalidDataException($"{propNames[0]} doesn't have {propNames[1]} property");
@ -326,6 +362,43 @@ namespace MiniExcelLibs.OpenXml
break;
}
else if (cellValue is DataTable)
{
var dt = cellValue as DataTable;
if (xRowInfo.CellIEnumerableValues == null)
{
xRowInfo.IEnumerablePropName = propNames[0];
xRowInfo.IEnumerableGenricType = typeof(DataRow);
xRowInfo.IsDataTable = true;
xRowInfo.CellIEnumerableValues = dt.Rows.Cast<DataRow>(); //TODO: need to optimize performance
maxRowIndexDiff = dt.Rows.Count <= 1 ? 0 : dt.Rows.Count;
xRowInfo.PropsMap = dt.Columns.Cast<DataColumn>().ToDictionary(col => col.ColumnName, col =>
new PropInfo { UnderlyingTypePropType = Nullable.GetUnderlyingType(col.DataType) }
);
}
var column = dt.Columns[propNames[1]];
var type = Nullable.GetUnderlyingType(column.DataType) ?? column.DataType; //avoid nullable
if (!xRowInfo.PropsMap.ContainsKey(propNames[1]))
throw new InvalidDataException($"{propNames[0]} doesn't have {propNames[1]} property");
if (isMultiMatch)
{
c.SetAttribute("t", "str");
}
else if (Helpers.IsNumericType(type))
{
c.SetAttribute("t", "n");
}
else if (Type.GetTypeCode(type) == TypeCode.Boolean)
{
c.SetAttribute("t", "b");
}
else if (Type.GetTypeCode(type) == TypeCode.DateTime)
{
c.SetAttribute("t", "str");
}
}
else
{
var cellValueStr = ExcelOpenXmlUtils.EncodeXML(cellValue);

View File

@ -3,6 +3,7 @@ using MiniExcelLibs;
using MiniExcelLibs.Tests.Utils;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using Xunit;
@ -11,6 +12,147 @@ namespace MiniExcelTests
{
public class MiniExcelTemplateTests
{
[Fact]
public void DatatableTemptyRowTest()
{
{
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
var templatePath = @"..\..\..\..\..\samples\xlsx\TestTemplateComplex.xlsx";
var managers = new DataTable();
{
managers.Columns.Add("name");
managers.Columns.Add("department");
}
var employees = new DataTable();
{
employees.Columns.Add("name");
employees.Columns.Add("department");
}
var value = new Dictionary<string, object>()
{
["title"] = "FooCompany",
["managers"] = managers,
["employees"] = employees
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);
{
var rows = MiniExcel.Query(path).ToList();
var demension = Helpers.GetFirstSheetDimensionRefValue(path);
Assert.Equal("A1:C5", demension);
}
}
{
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
var templatePath = @"..\..\..\..\..\samples\xlsx\TestTemplateComplex.xlsx";
var managers = new DataTable();
{
managers.Columns.Add("name");
managers.Columns.Add("department");
managers.Rows.Add("Jack", "HR");
}
var employees = new DataTable();
{
employees.Columns.Add("name");
employees.Columns.Add("department");
employees.Rows.Add("Wade", "HR");
}
var value = new Dictionary<string, object>()
{
["title"] = "FooCompany",
["managers"] = managers,
["employees"] = employees
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);
{
var rows = MiniExcel.Query(path).ToList();
var demension = Helpers.GetFirstSheetDimensionRefValue(path);
Assert.Equal("A1:C5", demension);
}
}
}
[Fact]
public void DatatableTest()
{
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
var templatePath = @"..\..\..\..\..\samples\xlsx\TestTemplateComplex.xlsx";
var managers = new DataTable();
{
managers.Columns.Add("name");
managers.Columns.Add("department");
managers.Rows.Add("Jack", "HR");
managers.Rows.Add("Loan", "IT");
}
var employees = new DataTable();
{
employees.Columns.Add("name");
employees.Columns.Add("department");
employees.Rows.Add("Wade", "HR");
employees.Rows.Add("Felix", "HR");
employees.Rows.Add("Eric", "IT");
employees.Rows.Add("Keaton", "IT");
}
var value = new Dictionary<string, object>()
{
["title"] = "FooCompany",
["managers"] = managers,
["employees"] = employees
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);
{
var rows = MiniExcel.Query(path).ToList();
var demension = Helpers.GetFirstSheetDimensionRefValue(path);
Assert.Equal("A1:C9", demension);
Assert.Equal(9, rows.Count);
Assert.Equal("FooCompany", rows[0].A);
Assert.Equal("Jack", rows[2].B);
Assert.Equal("HR", rows[2].C);
Assert.Equal("Loan", rows[3].B);
Assert.Equal("IT", rows[3].C);
Assert.Equal("Wade", rows[5].B);
Assert.Equal("HR", rows[5].C);
Assert.Equal("Felix", rows[6].B);
Assert.Equal("HR", rows[6].C);
Assert.Equal("Eric", rows[7].B);
Assert.Equal("IT", rows[7].C);
Assert.Equal("Keaton", rows[8].B);
Assert.Equal("IT", rows[8].C);
}
{
var rows = MiniExcel.Query(path, sheetName: "Sheet2").ToList();
Assert.Equal(9, rows.Count);
Assert.Equal("FooCompany", rows[0].A);
Assert.Equal("Jack", rows[2].B);
Assert.Equal("HR", rows[2].C);
Assert.Equal("Loan", rows[3].B);
Assert.Equal("IT", rows[3].C);
Assert.Equal("Wade", rows[5].B);
Assert.Equal("HR", rows[5].C);
Assert.Equal("Felix", rows[6].B);
Assert.Equal("HR", rows[6].C);
Assert.Equal("Eric", rows[7].B);
Assert.Equal("IT", rows[7].C);
Assert.Equal("Keaton", rows[8].B);
Assert.Equal("IT", rows[8].C);
var demension = Helpers.GetFirstSheetDimensionRefValue(path);
Assert.Equal("A1:C9", demension);
}
}
[Fact]
public void DapperTemplateTest()
{