mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-11-30 02:47:39 +08:00
- [New] SaveAsByTemplate support input IEnmerable<IDicionary<string,object>> or DapperRows
parameters [#201](https://github.com/shps951023/MiniExcel/issues/201)
This commit is contained in:
parent
61d816f477
commit
fbfca6354e
@ -8,6 +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)
|
||||
- [Bug] Fix after stream SaveAs/SaveAsByTemplate, miniexcel will close stream [#200](https://github.com/shps951023/MiniExcel/issues/200)
|
||||
|
||||
### 0.13.0
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
### 0.13.1
|
||||
- [New] SaveAsByTemplate 支持读取模板 byte[],方便缓存跟支持多用户同时读取同一个模板 #189
|
||||
- [New] SaveAsByTemplate 支持传入 `IEnmerable<IDicionary<string,object>> 或 DapperRows` 参数 [#201](https://github.com/shps951023/MiniExcel/issues/201)
|
||||
- [Bug] 修正使用 stream SaveAs/SaveAsByTemplate 系统会自动关闭流 stream [#200](https://github.com/shps951023/MiniExcel/issues/200)
|
||||
|
||||
### 0.13.0
|
||||
|
@ -9,6 +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)
|
||||
- [Bug] 修正使用 stream SaveAs/SaveAsByTemplate 系統會自動關閉流 stream [#200](https://github.com/shps951023/MiniExcel/issues/200)
|
||||
|
||||
### 0.13.0
|
||||
|
@ -21,12 +21,178 @@ namespace MiniExcelLibs.OpenXml
|
||||
public string IEnumerablePropName { get; set; }
|
||||
public XmlElement Row { get; set; }
|
||||
public Type IEnumerableGenricType { get; set; }
|
||||
public IDictionary<string, PropertyInfo> PropsMap { get; set; }
|
||||
public IDictionary<string, PropInfo > PropsMap { get; set; }
|
||||
public bool IsDictionary { get; set; }
|
||||
public IEnumerable CellIEnumerableValues { get; set; }
|
||||
}
|
||||
|
||||
internal class PropInfo
|
||||
{
|
||||
public PropertyInfo PropertyInfo { get; set; }
|
||||
public Type UnderlyingTypePropType { get; set; }
|
||||
}
|
||||
|
||||
private List<XRowInfo> XRowInfos { get; set; }
|
||||
|
||||
private void GenerateSheetXmlImpl(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream, Dictionary<string, object> inputMaps, List<string> sharedStrings, XmlWriterSettings xmlWriterSettings = null)
|
||||
{
|
||||
var doc = new XmlDocument();
|
||||
doc.Load(sheetStream);
|
||||
sheetStream.Dispose();
|
||||
|
||||
sheetZipEntry.Delete(); // ZipArchiveEntry can't update directly, so need to delete then create logic
|
||||
|
||||
var worksheet = doc.SelectSingleNode("/x:worksheet", _ns);
|
||||
var sheetData = doc.SelectSingleNode("/x:worksheet/x:sheetData", _ns);
|
||||
|
||||
var newSheetData = sheetData.Clone(); //avoid delete lost data
|
||||
var rows = newSheetData.SelectNodes($"x:row", _ns);
|
||||
|
||||
ReplaceSharedStringsToStr(sharedStrings, ref rows);
|
||||
|
||||
//Update dimension && Check if the column contains a collection and get type and properties infomations
|
||||
UpdateDimensionAndGetCollectionPropertiesInfos(inputMaps, ref doc, ref rows);
|
||||
|
||||
#region Render cell values
|
||||
|
||||
//Q.Why so complex?
|
||||
//A.Because try to use string stream avoid OOM when rendering rows
|
||||
sheetData.RemoveAll();
|
||||
sheetData.InnerText = "{{{{{{split}}}}}}"; //TODO: bad smell
|
||||
var prefix = string.IsNullOrEmpty(sheetData.Prefix) ? "" : $"{sheetData.Prefix}:";
|
||||
var endPrefix = string.IsNullOrEmpty(sheetData.Prefix) ? "" : $":{sheetData.Prefix}"; //![image](https://user-images.githubusercontent.com/12729184/115000066-fd02b300-9ed4-11eb-8e65-bf0014015134.png)
|
||||
var contents = doc.InnerXml.Split(new string[] { $"<{prefix}sheetData>{{{{{{{{{{{{split}}}}}}}}}}}}</{prefix}sheetData>" }, StringSplitOptions.None); ;
|
||||
using (var writer = new StreamWriter(stream, Encoding.UTF8))
|
||||
{
|
||||
writer.Write(contents[0]);
|
||||
writer.Write($"<{prefix}sheetData>"); // prefix problem
|
||||
int originRowIndex;
|
||||
int rowIndexDiff = 0;
|
||||
foreach (var xInfo in XRowInfos)
|
||||
{
|
||||
var row = xInfo.Row;
|
||||
|
||||
//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;
|
||||
newRow.SetAttribute("r", newRowIndex.ToString());
|
||||
newRow.InnerXml = row.InnerXml.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString());
|
||||
|
||||
if (xInfo.IsDictionary)
|
||||
{
|
||||
var dic = item as IDictionary<string, object>;
|
||||
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 = dic[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))
|
||||
{
|
||||
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
|
||||
{
|
||||
foreach (var propInfo in xInfo.PropsMap)
|
||||
{
|
||||
var prop = propInfo.Value.PropertyInfo;
|
||||
|
||||
var key = $"{{{{{xInfo.IEnumerablePropName}.{prop.Name}}}}}";
|
||||
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 = prop.GetValue(item);
|
||||
if (cellValue == null)
|
||||
{
|
||||
newRow.InnerXml = newRow.InnerXml.Replace(key, "");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var cellValueStr = ExcelOpenXmlUtils.EncodeXML(cellValue);
|
||||
var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// note: only first time need add diff ![image](https://user-images.githubusercontent.com/12729184/114494728-6bceda80-9c4f-11eb-9685-8b5ed054eabe.png)
|
||||
if (!first)
|
||||
rowIndexDiff++;
|
||||
first = false;
|
||||
|
||||
newRowIndex++;
|
||||
writer.Write(CleanXml(newRow.OuterXml, endPrefix));
|
||||
newRow = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
row.SetAttribute("r", newRowIndex.ToString());
|
||||
row.InnerXml = row.InnerXml.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString());
|
||||
writer.Write(CleanXml(row.OuterXml, endPrefix));
|
||||
}
|
||||
}
|
||||
writer.Write($"</{prefix}sheetData>");
|
||||
writer.Write(contents[1]);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
private static string CleanXml(string xml, string endPrefix)
|
||||
{
|
||||
//TODO: need to optimize
|
||||
return xml
|
||||
.Replace("xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\"", "")
|
||||
.Replace($"xmlns{endPrefix}=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"", "");
|
||||
}
|
||||
|
||||
private void ReplaceSharedStringsToStr(List<string> sharedStrings, ref XmlNodeList rows)
|
||||
{
|
||||
foreach (XmlElement row in rows)
|
||||
@ -109,7 +275,19 @@ namespace MiniExcelLibs.OpenXml
|
||||
{
|
||||
xRowInfo.IEnumerablePropName = propNames[0];
|
||||
xRowInfo.IEnumerableGenricType = element.GetType();
|
||||
xRowInfo.PropsMap = xRowInfo.IEnumerableGenricType.GetProperties().ToDictionary(s => s.Name, s => s);
|
||||
if (element is IDictionary<string, object>)
|
||||
{
|
||||
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) } ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
xRowInfo.PropsMap = xRowInfo.IEnumerableGenricType.GetProperties()
|
||||
.ToDictionary(s => s.Name, s => new PropInfo { PropertyInfo = s, UnderlyingTypePropType = Nullable.GetUnderlyingType(s.PropertyType) ?? s.PropertyType });
|
||||
}
|
||||
}
|
||||
// ==== get demension max rowindex ====
|
||||
if (!first) //avoid duplicate add first one, this row not add status ![image](https://user-images.githubusercontent.com/12729184/114851829-d2512580-9e14-11eb-8e7d-520c89a7ebee.png)
|
||||
@ -124,7 +302,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
|
||||
// auto check type https://github.com/shps951023/MiniExcel/issues/177
|
||||
var prop = xRowInfo.PropsMap[propNames[1]];
|
||||
var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; //avoid nullable
|
||||
var type = prop.UnderlyingTypePropType; //avoid nullable
|
||||
//
|
||||
if (!xRowInfo.PropsMap.ContainsKey(propNames[1]))
|
||||
throw new InvalidDataException($"{propNames[0]} doesn't have {propNames[1]} property");
|
||||
|
@ -6,6 +6,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
@ -93,121 +94,5 @@ namespace MiniExcelLibs.OpenXml
|
||||
_archive.ZipFile.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateSheetXmlImpl(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream, Dictionary<string, object> inputMaps, List<string> sharedStrings, XmlWriterSettings xmlWriterSettings = null)
|
||||
{
|
||||
var doc = new XmlDocument();
|
||||
doc.Load(sheetStream);
|
||||
sheetStream.Dispose();
|
||||
|
||||
sheetZipEntry.Delete(); // ZipArchiveEntry can't update directly, so need to delete then create logic
|
||||
|
||||
var worksheet = doc.SelectSingleNode("/x:worksheet", _ns);
|
||||
var sheetData = doc.SelectSingleNode("/x:worksheet/x:sheetData", _ns);
|
||||
|
||||
var newSheetData = sheetData.Clone(); //avoid delete lost data
|
||||
var rows = newSheetData.SelectNodes($"x:row", _ns);
|
||||
|
||||
ReplaceSharedStringsToStr(sharedStrings, ref rows);
|
||||
|
||||
//Update dimension && Check if the column contains a collection and get type and properties infomations
|
||||
UpdateDimensionAndGetCollectionPropertiesInfos(inputMaps, ref doc, ref rows);
|
||||
|
||||
#region Render cell values
|
||||
|
||||
//Q.Why so complex?
|
||||
//A.Because try to use string stream avoid OOM when rendering rows
|
||||
sheetData.RemoveAll();
|
||||
sheetData.InnerText = "{{{{{{split}}}}}}"; //TODO: bad smell
|
||||
var prefix = string.IsNullOrEmpty(sheetData.Prefix) ? "" : $"{sheetData.Prefix}:";
|
||||
var endPrefix = string.IsNullOrEmpty(sheetData.Prefix) ? "" : $":{sheetData.Prefix}"; //![image](https://user-images.githubusercontent.com/12729184/115000066-fd02b300-9ed4-11eb-8e65-bf0014015134.png)
|
||||
var contents = doc.InnerXml.Split(new string[] { $"<{prefix}sheetData>{{{{{{{{{{{{split}}}}}}}}}}}}</{prefix}sheetData>" }, StringSplitOptions.None); ;
|
||||
using (var writer = new StreamWriter(stream, Encoding.UTF8))
|
||||
{
|
||||
writer.Write(contents[0]);
|
||||
writer.Write($"<{prefix}sheetData>"); // prefix problem
|
||||
int originRowIndex;
|
||||
int rowIndexDiff = 0;
|
||||
foreach (var xInfo in XRowInfos)
|
||||
{
|
||||
var row = xInfo.Row;
|
||||
|
||||
//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;
|
||||
newRow.SetAttribute("r", newRowIndex.ToString());
|
||||
newRow.InnerXml = row.InnerXml.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString());
|
||||
|
||||
foreach (var propInfo in xInfo.PropsMap)
|
||||
{
|
||||
var prop = propInfo.Value;
|
||||
|
||||
var key = $"{{{{{xInfo.IEnumerablePropName}.{prop.Name}}}}}";
|
||||
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 = prop.GetValue(item);
|
||||
if (cellValue == null)
|
||||
{
|
||||
newRow.InnerXml = newRow.InnerXml.Replace(key, "");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var cellValueStr = ExcelOpenXmlUtils.EncodeXML(cellValue);
|
||||
var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
|
||||
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);
|
||||
}
|
||||
|
||||
// note: only first time need add diff ![image](https://user-images.githubusercontent.com/12729184/114494728-6bceda80-9c4f-11eb-9685-8b5ed054eabe.png)
|
||||
if (!first)
|
||||
rowIndexDiff++;
|
||||
first = false;
|
||||
|
||||
newRowIndex++;
|
||||
writer.Write(CleanXml(newRow.OuterXml, endPrefix));
|
||||
newRow = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
row.SetAttribute("r", newRowIndex.ToString());
|
||||
row.InnerXml = row.InnerXml.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString());
|
||||
writer.Write(CleanXml(row.OuterXml, endPrefix));
|
||||
}
|
||||
}
|
||||
writer.Write($"</{prefix}sheetData>");
|
||||
writer.Write(contents[1]);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
private static string CleanXml(string xml,string endPrefix)
|
||||
{
|
||||
//TODO: need to optimize
|
||||
return xml
|
||||
.Replace("xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\"", "")
|
||||
.Replace($"xmlns{endPrefix}=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ namespace MiniExcelLibs.Tests
|
||||
{
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||
using (var connection = GetConnection("Data Source=:memory:"))
|
||||
using (var connection = Db.GetConnection("Data Source=:memory:"))
|
||||
{
|
||||
var rows = connection.Query(@"with cte as (select 1 id,2 val) select * from cte where 1=2");
|
||||
MiniExcel.SaveAs(path, rows);
|
||||
@ -816,7 +816,7 @@ namespace MiniExcelLibs.Tests
|
||||
|
||||
|
||||
// Dapper Query
|
||||
using (var connection = GetConnection("Data Source=:memory:"))
|
||||
using (var connection = Db.GetConnection("Data Source=:memory:"))
|
||||
{
|
||||
var rows = connection.Query(@"select 'MiniExcel' as Column1,1 as Column2 union all select 'Github',2");
|
||||
MiniExcel.SaveAs(path, rows);
|
||||
@ -837,7 +837,7 @@ namespace MiniExcelLibs.Tests
|
||||
File.Delete(path);
|
||||
|
||||
// Empty
|
||||
using (var connection = GetConnection("Data Source=:memory:"))
|
||||
using (var connection = Db.GetConnection("Data Source=:memory:"))
|
||||
{
|
||||
var rows = connection.Query(@"with cte as (select 'MiniExcel' as Column1,1 as Column2 union all select 'Github',2)select * from cte where 1=2").ToList();
|
||||
MiniExcel.SaveAs(path, rows);
|
||||
@ -860,7 +860,7 @@ namespace MiniExcelLibs.Tests
|
||||
|
||||
|
||||
// ToList
|
||||
using (var connection = GetConnection("Data Source=:memory:"))
|
||||
using (var connection = Db.GetConnection("Data Source=:memory:"))
|
||||
{
|
||||
var rows = connection.Query(@"select 'MiniExcel' as Column1,1 as Column2 union all select 'Github',2").ToList();
|
||||
MiniExcel.SaveAs(path, rows);
|
||||
@ -950,11 +950,6 @@ namespace MiniExcelLibs.Tests
|
||||
File.Delete(path);
|
||||
}
|
||||
|
||||
private static SQLiteConnection GetConnection(string connectionString)
|
||||
{
|
||||
return new SQLiteConnection(connectionString);
|
||||
}
|
||||
|
||||
[Fact()]
|
||||
public void SQLiteInsertTest()
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MiniExcelLibs;
|
||||
using Dapper;
|
||||
using MiniExcelLibs;
|
||||
using MiniExcelLibs.Tests.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -10,6 +11,146 @@ namespace MiniExcelTests
|
||||
{
|
||||
public class MiniExcelTemplateTests
|
||||
{
|
||||
[Fact]
|
||||
public void DapperTemplateTest()
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
|
||||
var templatePath = @"..\..\..\..\..\samples\xlsx\TestTemplateComplex.xlsx";
|
||||
|
||||
var connection = Db.GetConnection("Data Source=:memory:");
|
||||
var value = new Dictionary<string, object>()
|
||||
{
|
||||
["title"] = "FooCompany",
|
||||
["managers"] = connection.Query("select 'Jack' name,'HR' department union all select 'Loan','IT'"),
|
||||
["employees"] = connection.Query(@"select 'Wade' name,'HR' department union all select 'Felix','HR' union all select 'Eric','IT' union all select 'Keaton','IT'")
|
||||
};
|
||||
MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
{
|
||||
var rows = MiniExcel.Query(path).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);
|
||||
}
|
||||
|
||||
{
|
||||
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 DictionaryTemplateTest()
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
|
||||
var templatePath = @"..\..\..\..\..\samples\xlsx\TestTemplateComplex.xlsx";
|
||||
|
||||
var value = new Dictionary<string, object>()
|
||||
{
|
||||
["title"] = "FooCompany",
|
||||
["managers"] = new[] {
|
||||
new Dictionary<string, object>{["name"]="Jack",["department"]="HR"},
|
||||
new Dictionary<string, object>{["name"]="Loan",["department"]="IT"}
|
||||
},
|
||||
["employees"] = new[] {
|
||||
new Dictionary<string, object>{["name"]="Wade",["department"]="HR"},
|
||||
new Dictionary<string, object>{["name"]="Felix",["department"]="HR"},
|
||||
new Dictionary<string, object>{["name"]="Eric",["department"]="IT"},
|
||||
new Dictionary<string, object>{["name"]="Keaton",["department"]="IT"}
|
||||
}
|
||||
};
|
||||
MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
{
|
||||
var rows = MiniExcel.Query(path).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);
|
||||
}
|
||||
|
||||
{
|
||||
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 TestGithubProject()
|
||||
{
|
||||
|
16
tests/MiniExcelTests/Utils/Db.cs
Normal file
16
tests/MiniExcelTests/Utils/Db.cs
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
This Class Modified from ExcelDataReader : https://github.com/ExcelDataReader/ExcelDataReader
|
||||
**/
|
||||
namespace MiniExcelLibs.Tests.Utils
|
||||
{
|
||||
using System.Data.SQLite;
|
||||
|
||||
internal static class Db
|
||||
{
|
||||
internal static SQLiteConnection GetConnection(string connectionString)
|
||||
{
|
||||
return new SQLiteConnection(connectionString);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,6 +6,7 @@ namespace MiniExcelLibs.Tests.Utils
|
||||
using MiniExcelLibs.OpenXml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
using System.Dynamic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
Loading…
Reference in New Issue
Block a user