Skip to content

Commit

Permalink
Merge pull request #3 from doroudi/Feature/improve_export_performance
Browse files Browse the repository at this point in the history
improve export performance
  • Loading branch information
doroudi authored Dec 17, 2022
2 parents ad15571 + 053d3c4 commit 2e21197
Show file tree
Hide file tree
Showing 16 changed files with 221 additions and 151 deletions.
Binary file added ExcelMapper.Test/AppData/data.xlsx
Binary file not shown.
26 changes: 26 additions & 0 deletions ExcelMapper.Test/MapperProfiles/EmployeeMapperProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using ExcelMapper.ExcelMapper;
using ExcelMapper.Test.Models;
using ExcelMapper.Validations;

namespace ExcelMapper.Test.MapperProfiles
{
public class EmployeeMapperProfile : ExcelImportMapper<Employee>
{
public EmployeeMapperProfile()
{
CreateMap()
.ForMember(x => x.Id,
opt => opt.MapFromCol("A").UseValidation(GeneralValidations.NotNull))
.ForMember(x => x.Name,
opt => opt.MapFromCol("B").UseValidation(GeneralValidations.NotNull))
.ForMember(x => x.Family,
opt => opt.MapFromCol("C").UseValidation(GeneralValidations.NotNull))
.ForMember(x => x.JoinDate,
opt => opt.MapFromCol("D").UseValidation(GeneralValidations.NotNull))
.ForMember(x => x.NationalId,
opt => opt.MapFromCol("E").UseValidation(GeneralValidations.NotNull))
.ForMember(x => x.Address,
opt => opt.MapFromCol("F").UseValidation(GeneralValidations.NotNull));
}
}
}
25 changes: 25 additions & 0 deletions ExcelMapper.Test/MapperProfiles/ExportProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using ExcelMapper.ExcelExporter;
using ExcelMapper.Test.Models;
using NPOI.SS.UserModel;

namespace ExcelMapper.Test.MapperProfiles
{
public class ExportProfile: ExportMapper<Employee>
{
public ExportProfile(IWorkbook workbook): base(workbook)
{
CreateMap()
.ForColumn("A", x => x.Name, opt => opt.WithTitle("Name"))
.ForColumn("B", x => x.Family, opt => opt.WithTitle("Family"))
.ForColumn("C", x => x.BirthDate, opt => opt.WithTitle("BirthDate").UseAction(ConvertToPersian))
.ForColumn("D", x => x.Address, opt => opt.WithTitle("Address"))
.ForColumn("E", x => x.Name, opt => opt.WithTitle("NAME").UseAction(x => x.ToUpper()));
// .ForColumn("B", opt => opt.MapFrom<Employee>(x => x.Name));
}

private string ConvertToPersian(DateTime arg)
{
return arg.ToShortDateString();
}
}
}
26 changes: 26 additions & 0 deletions ExcelMapper.Test/Models/Employee.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExcelMapper.Test.Models
{
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
public string Family { get; set; }
public string Mobile { get; set; }
public string NationalId { get; set; }
public string Address { get; set; }
public int Grade { get; set; }
public DateTime JoinDate { get; set; }
public DateTime BirthDate { get; set; }

public override string ToString()
{
return $"({Name} {Family}, {BirthDate:D})";
}
}
}
27 changes: 27 additions & 0 deletions ExcelMapper.Test/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using ExcelMapper;
using ExcelMapper.ExcelParser;
using ExcelMapper.Logger;
using ExcelMapper.Test.MapperProfiles;
using ExcelMapper.Test.Models;

var fileName = @"AppData\data.xlsx";
ExcelParser<Employee> parser = new (new FileInfo(fileName), new EmployeeMapperProfile());
var employees = parser.GetItems();


foreach (var emplyee in employees)
{
Console.WriteLine(emplyee);
}

var logger = new ExcelLogger(fileName,"EF");
logger.LogInvalidColumns(parser.InvalidRows);

var exporter = new ExcelWriter();

exporter.AddSheet(
new ExportProfile(exporter.WorkBook),
x => x.SetRtl().UseData(employees).UseDefaultHeaderStyle().Build()
);

exporter.SaveToFile("D:\\excel\\EXPORT.xlsx");
20 changes: 20 additions & 0 deletions ExcelMapper.Test/YummyCode.ExcelMapper.Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ExcelMapper\YummyCode.ExcelMapper.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="AppData\data.xlsx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions ExcelMapper.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YummyCode.ExcelMapper.Test", "ExcelMapper.Test\YummyCode.ExcelMapper.Test.csproj", "{8D343B10-CD04-43A2-A70B-8BED34DCB78E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -22,6 +24,10 @@ Global
{B72766E3-836D-48EA-ABF4-38C1F16F0DCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B72766E3-836D-48EA-ABF4-38C1F16F0DCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B72766E3-836D-48EA-ABF4-38C1F16F0DCE}.Release|Any CPU.Build.0 = Release|Any CPU
{8D343B10-CD04-43A2-A70B-8BED34DCB78E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D343B10-CD04-43A2-A70B-8BED34DCB78E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D343B10-CD04-43A2-A70B-8BED34DCB78E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D343B10-CD04-43A2-A70B-8BED34DCB78E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
14 changes: 6 additions & 8 deletions ExcelMapper/ExcelExporter/ExcelExporter{T}.cs
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
using ExcelMapper.ExcelExporter;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.XSSF.Streaming;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace ExcelMapper
{
public class ExcelWriter
{
#region Fields
private readonly XSSFWorkbook _workBook;
private readonly SXSSFWorkbook _workBook;
#endregion

public XSSFWorkbook WorkBook => _workBook;
public SXSSFWorkbook WorkBook => _workBook;

#region Constructor
public ExcelWriter()
{
_workBook = new XSSFWorkbook();
_workBook = new SXSSFWorkbook();
}
#endregion

#region Methods
/// <summary>
/// Add new sheet using SheetBuilder
/// </summary>
/// <param name="sheet"></param>
/// <param name="mapper">mapper instance of TSource</param>
/// <param name="builder">sheet builder</param>
/// <returns></returns>
public ExcelWriter AddSheet<TSource>(IExportMapper<TSource> mapper, Action<SheetBuilder<TSource>> builder) where TSource : new()
{
Expand Down
112 changes: 41 additions & 71 deletions ExcelMapper/ExcelExporter/ExportMapper.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
using ExcelMapper.Models;
using ExcelMapper.Util;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ExcelMapper.ExcelExporter
{
public abstract class ExportMapper<TSource> : IExportMapper<TSource> where TSource : new()
{
protected IWorkbook _workbook;
private IExportMappingExpression<TSource> _mappingExpression;
private Dictionary<int, List<Delegate>> _compiledActions;

public ExportMapper(IWorkbook workbook)
{
_workbook = workbook;
}
private IExportMappingExpression<TSource> _mappingExpression;

public List<CellMappingInfo> Mappings =>
_mappingExpression.Mappings;
Expand All @@ -23,32 +24,51 @@ public IExportMappingExpression<TSource> CreateMap()
{
var expression = new ExportMappingExpression<TSource>();
_mappingExpression = expression;
_compiledActions = new Dictionary<int, List<Delegate>>();
return expression;
}

public IRow Map(TSource data, IRow row)
public void Map(TSource data, IRow row)
{
if (_compiledActions.Count == 0)
{
CompileMappingActions();
}

var mappingCols = _mappingExpression.Mappings;
foreach (var colMapping in mappingCols)
{
try
{
var converted = AddMappingAction(data, colMapping);
var converted = ExecuteMappingAction(data, colMapping);
SetCellValue(row, colMapping, converted);
}
//TODO Check
catch (Exception ex)
{
#if DEBUG
Debugger.Break();
#endif

throw;
}
}
return row;

}

private void CompileMappingActions()
{
foreach (var mapping in _mappingExpression.Mappings)
{
if (mapping == null) { continue; }
var mappingCompiledActions = new List<Delegate>();
foreach (var action in mapping.Actions)
mappingCompiledActions.Add(action.Compile());

if (mappingCompiledActions.Any())
{
_compiledActions.Add(mapping.Column, mappingCompiledActions);
}
}
}


private static void SetCellValue(IRow row, CellMappingInfo colMapping, object converted)
{
string cellValue = string.Empty;
Expand All @@ -62,7 +82,7 @@ private static void SetCellValue(IRow row, CellMappingInfo colMapping, object co
cellValue = colMapping.DefaultValue;

// TODO: should check for value is correct column name in excel
if (colMapping.Column == null) return;
if (colMapping.Column < 0) return;

var cell = row.CreateCell(colMapping.Column);
if (colMapping.Style != null)
Expand All @@ -71,79 +91,29 @@ private static void SetCellValue(IRow row, CellMappingInfo colMapping, object co
cell.SetCellValue(cellValue);
}

private static object AddMappingAction(TSource data, CellMappingInfo mapping)
private object ExecuteMappingAction(TSource data, CellMappingInfo mapping)
{
data = data ?? throw new ArgumentNullException(nameof(data));
mapping = mapping ?? throw new ArgumentNullException(nameof(mapping));

//data = data ?? throw new ArgumentNullException(nameof(data));
//mapping = mapping ?? throw new ArgumentNullException(nameof(mapping));
var value = data?.GetType().GetProperty(mapping.Property?.Name).GetValue(data, null);
object converted = value ?? string.Empty;
if (mapping.Actions != null)
foreach (var action in mapping.Actions)
converted = action.Compile().DynamicInvoke(value);
if (!_compiledActions.ContainsKey(mapping.Column)) return value;
object converted = value;
foreach (var action in _compiledActions[mapping.Column])
{
converted = action.DynamicInvoke(converted);
}

return converted;
}


public IRow MapHeader(IRow headerRow)
public void MapHeader(ref IRow headerRow)
{
var mappingCols = _mappingExpression.Mappings;
foreach (var mapping in mappingCols)
{
headerRow.CreateCell(mapping.Column).SetCellValue(mapping.Title);
}

return headerRow;
}
#region CreateStyle
//private ICellStyle CreateStyle(IWorkbook workbook, CellStyleOptions style)
//{
// var customStyle = workbook.CreateCellStyle();
// if (style.FontFamily != null)
// {
// var font = workbook.GetCustomFont(style.FontFamily);
// customStyle.SetFont(font);
// }

// if (style.Alignment != null)
// {
// customStyle.Alignment = style.Alignment.Value;
// }

// if (style.VerticalAlignment != null)
// {
// customStyle.VerticalAlignment = style.VerticalAlignment.Value;
// }

// if (style.BackgroundColor != null)
// {
// customStyle.FillBackgroundColor = style.BackgroundColor.Index;
// }

// if (style.BorderStyle != null)
// {
// customStyle.BorderLeft =
// customStyle.BorderRight =
// customStyle.BorderTop =
// customStyle.BorderBottom =
// BorderStyle.Thin;
// }

// if (style.BorderColor != null)
// {
// customStyle.BottomBorderColor =
// customStyle.LeftBorderColor =
// customStyle.RightBorderColor =
// customStyle.TopBorderColor =
// style.BorderColor.Index;
// }

// return customStyle;

//}
#endregion


}
}
Loading

0 comments on commit 2e21197

Please sign in to comment.