Skip to content

Commit

Permalink
🐛 Fix mapping issues in TestApp
Browse files Browse the repository at this point in the history
refactor implementation
fix auto column size issue
use syntax updates in .Net 8
refactor code structure
add get columns list feature
  • Loading branch information
doroudi committed Feb 22, 2024
1 parent a3dcf7c commit 506a404
Show file tree
Hide file tree
Showing 24 changed files with 328 additions and 352 deletions.
6 changes: 6 additions & 0 deletions .idea/.idea.ExcelMapper/.idea/developer-tools.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 1 addition & 11 deletions ExcelMapper.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32407.343
MinimumVisualStudioVersion = 10.0.40219.1
<<<<<<< HEAD
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YummyCode.ExcelMapper.Importer", "src\YummyCode.ExcelMapper.Importer\YummyCode.ExcelMapper.Importer.csproj", "{B72766E3-836D-48EA-ABF4-38C1F16F0DCE}"
=======
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YummyCode.ExcelMapper.Importer", "ExcelMapper\YummyCode.ExcelMapper.Importer.csproj", "{B72766E3-836D-48EA-ABF4-38C1F16F0DCE}"
>>>>>>> 452e969fed67e87b821b76b42a2de365434c852f
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5D816DBB-F928-4AAC-AC10-B4170D353844}"
ProjectSection(SolutionItems) = preProject
Expand All @@ -16,7 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YummyCode.ExcelMapper.Test", "test\ExcelMapper.Test\YummyCode.ExcelMapper.Test.csproj", "{8D343B10-CD04-43A2-A70B-8BED34DCB78E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YummyCode.ExcelMapper.TestApp", "test\ExcelMapper.Test\YummyCode.ExcelMapper.TestApp.csproj", "{8D343B10-CD04-43A2-A70B-8BED34DCB78E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YummyCode.ExcelMapper.Exporter", "src\YummyCode.ExcelMapper.Exporter\YummyCode.ExcelMapper.Exporter.csproj", "{B051350E-13E1-4A0C-B1DE-C56DF0109A8E}"
EndProject
Expand All @@ -28,12 +24,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5DD08BCF-3A6
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{10C4E5AE-0A60-4978-B708-3A6076ACEE10}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YummyCode.ExcelMapper.Exporter", "YummyCode.ExcelMapper.Exporter\YummyCode.ExcelMapper.Exporter.csproj", "{B051350E-13E1-4A0C-B1DE-C56DF0109A8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YummyCode.ExcelMapper.Shared", "YummyCode.ExcelMapper.Shared\YummyCode.ExcelMapper.Shared.csproj", "{E3C9F767-3DA2-4C10-BC19-BF49E63243C5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YummyCode.ExcelMapper.Logger", "YummyCode.ExcelMapper.Logger\YummyCode.ExcelMapper.Logger.csproj", "{2CDAA3F2-2812-44C5-AD8B-27B24CC0D2F4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
5 changes: 1 addition & 4 deletions src/YummyCode.ExcelMapper.Exporter/ExcelExporter{T}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ namespace YummyCode.ExcelMapper.Exporter
{
public class ExcelWriter
{
public SXSSFWorkbook WorkBook { get; } = new();
private SXSSFWorkbook WorkBook { get; } = new();

#region Methods
/// <summary>
/// Add new sheet using SheetBuilder
/// </summary>
Expand Down Expand Up @@ -41,7 +40,5 @@ public void SaveToFile(string fileName)
WorkBook.Write(fileStream);
GC.Collect();
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,28 @@ namespace YummyCode.ExcelMapper.Exporter
{
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;
_mappingExpression = new ExportMappingExpression<TSource>();
_compiledActions = new Dictionary<int, List<Delegate>>();
}
private readonly IExportMappingExpression<TSource> _mappingExpression = new ExportMappingExpression<TSource>();
private readonly Dictionary<int, List<Delegate>> _compiledActions = [];

public List<CellMappingInfo> Mappings =>
_mappingExpression.Mappings;

public IExportMappingExpression<TSource> CreateMap()
{
var expression = new ExportMappingExpression<TSource>();
_mappingExpression = expression;
_compiledActions = new Dictionary<int, List<Delegate>>();
return expression;
return _mappingExpression;
}

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

var mappingCols = _mappingExpression.Mappings;
foreach (var colMapping in mappingCols)
foreach (var colMapping in _mappingExpression.Mappings)
{
try
{
var converted = ExecuteMappingAction(data, colMapping);
SetCellValue(row, colMapping, converted);
}
//TODO Check
catch
{
throw;
}
var converted = ExecuteMappingAction(data, colMapping);
SetCellValue(row, colMapping, converted); // TODO: exception handling required
}
}

Expand All @@ -70,43 +50,50 @@ private void CompileMappingActions()

private static void SetCellValue(IRow row, CellMappingInfo colMapping, object converted)
{
// TODO: should check for value is correct column name in excel
if (colMapping.Column < 0) return;

var cellValue = string.Empty;
if (colMapping.ConstValue != null)
{
cellValue = colMapping.ConstValue;

}
else if (converted != null)
{
cellValue = converted.ToString();

}
else if (colMapping.DefaultValue != null)
{
cellValue = colMapping.DefaultValue;
}

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

var cell = row.CreateCell(colMapping.Column);
if (colMapping.Style != null)
{
cell.CellStyle = colMapping.Style;
}

cell.SetCellValue(cellValue);
}

private object ExecuteMappingAction(TSource data, CellMappingInfo 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);
if (!_compiledActions.ContainsKey(mapping.Column)) return value;
if (mapping?.Property?.Name == null)
throw new ArgumentException("Property not set");

var value = data?.GetType().GetProperty(mapping.Property.Name)?.GetValue(data, null);
if (!_compiledActions.ContainsKey(mapping.Column)) { return value; }
var converted = value;
for (var i = 0; i < _compiledActions[mapping.Column].Count; i++)
{
var action = _compiledActions[mapping.Column][i];
converted = action.DynamicInvoke(converted);
}

return converted;
}


public void MapHeader(ref IRow headerRow)
{
var mappingCols = _mappingExpression.Mappings;
Expand All @@ -119,7 +106,6 @@ public void MapHeader(ref IRow headerRow)
public IEnumerable<string> GetMappingColumns()
{
var items = _mappingExpression.Mappings;
//items.Reverse();
foreach (var item in items)
{
yield return item.Header ?? item.Property?.Name ?? "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,15 @@ public class ExportMappingExpression<TDestination> : IExportMappingExpression<TD
{
private ICellStyle _defaultStyle;

public List<CellMappingInfo> Mappings { get; } = new List<CellMappingInfo>();

public IExportMappingExpression<TDestination> ForAllMembers
(Action<ExportConfigurationExpression<TDestination>> memberOptions)
{

throw new NotImplementedException();
}

public IExportMappingExpression<TDestination> ForAllOtherMembers(Action<ExportConfigurationExpression<TDestination>> memberOptions)
{
// TODO: implement this
throw new NotImplementedException();
}
public List<CellMappingInfo> Mappings { get; } = [];

public ExportMappingExpression<TDestination> ForColumn<TMember>
(string column,
Expression<Func<TDestination, TMember>> destinationMember,
Action<ExportMemberConfigurationExpression<TDestination, TMember>> memberOptions = null)
{
var colRef = new CellReference(column);
var config = GetCellConfig(colRef.Col, destinationMember, memberOptions); ;
var config = GetCellConfig(colRef.Col, destinationMember, memberOptions);
Mappings.Add(config);
return this;
}
Expand All @@ -50,7 +37,8 @@ public ExportMappingExpression<TDestination> AddColumn<TMember>
return this;
}

private CellMappingInfo GetCellConfig<TMember>(int column, Expression<Func<TDestination, TMember>> destinationMember, Action<ExportMemberConfigurationExpression<TDestination, TMember>> memberOptions)
private CellMappingInfo GetCellConfig<TMember>(int column, Expression<Func<TDestination, TMember>> destinationMember,
Action<ExportMemberConfigurationExpression<TDestination, TMember>> memberOptions)
{
var memberName = ((MemberExpression)destinationMember.Body).Member.Name;
var property = typeof(TDestination).GetProperty(memberName);
Expand All @@ -71,9 +59,8 @@ private CellMappingInfo GetCellConfig<TMember>(int column, Expression<Func<TDest
Actions = expression.Actions,
Style = expression.CellStyle,
ConstValue = expression.ConstValue,
DefaultValue = expression.DefaultValue?.ToString()
DefaultValue = expression.DefaultValue
};
Mappings.Add(config);
return config;
}

Expand All @@ -88,7 +75,7 @@ private string GetAvailableColumn()
/// </summary>
/// <param name="colIndex">index of column in excel</param>
/// <returns>corresponding column name for colIndex</returns>
private string ColumnIndexToColumnLetter(int colIndex)
private static string ColumnIndexToColumnLetter(int colIndex)
{
var div = colIndex;
var colLetter = string.Empty;
Expand All @@ -104,15 +91,15 @@ private string ColumnIndexToColumnLetter(int colIndex)
public List<LambdaExpression> GetActions(PropertyInfo property)
{
return Mappings
.FirstOrDefault(x => x.Property.Name == property.Name)?
.Actions ?? new List<LambdaExpression>();
.FirstOrDefault(x => x.Property?.Name == property.Name)?
.Actions ?? [];
}

public CellMappingInfo this[PropertyInfo property]
{
get
{
return Mappings.FirstOrDefault(x => x.Property.Name == property.Name);
return Mappings.FirstOrDefault(x => x.Property?.Name == property.Name);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace YummyCode.ExcelMapper.Exporter
/// </summary>
/// <param name="data">object to map data from it</param>
/// <param name="row">Excel row to write mapped data to it</param>
/// <returns>instance of TDestionation class contains values from mapped from excel</returns>
/// <returns>instance of TDestination class contains values from mapped from excel</returns>
/// <exception cref="ExcelMappingException">throws on fail to map some properties from excel file</exception>
void Map(TDestination data, IRow row);
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ public interface IExportMappingExpression<TDestination>
ExportMappingExpression<TDestination> ForColumn<TMember>
(string col,
Expression<Func<TDestination, TMember>> destinationMember,
Action<ExportMemberConfigurationExpression<TDestination, TMember>>? memberOptions = null);


Action<ExportMemberConfigurationExpression<TDestination, TMember>> memberOptions = null);
ExportMappingExpression<TDestination> AddColumn<TMember>
(Expression<Func<TDestination, TMember>> destinationMember,
Action<ExportMemberConfigurationExpression<TDestination, TMember>>? memberOptions = null);
Action<ExportMemberConfigurationExpression<TDestination, TMember>> memberOptions = null);
ExportMappingExpression<TDestination> SetDefaultStyle(ICellStyle options);
List<LambdaExpression> GetActions(PropertyInfo propertyInfo);
public List<CellMappingInfo> Mappings { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using NPOI.SS.UserModel;
using NPOI.XSSF.Streaming;
using YummyCode.ExcelMapper.Shared.Models;

namespace YummyCode.ExcelMapper.Exporter
Expand Down Expand Up @@ -46,7 +49,12 @@ public SheetBuilder<TSource> UseDefaultHeaderStyle()
{
var headerStyle = _workBook.CreateCellStyle();
headerStyle.Alignment = HorizontalAlignment.Center;
headerStyle.BorderTop = headerStyle.BorderBottom = headerStyle.BorderLeft = headerStyle.BorderRight = BorderStyle.Thin;
headerStyle.BorderTop =
headerStyle.BorderBottom =
headerStyle.BorderLeft =
headerStyle.BorderRight =
BorderStyle.Thin;

headerStyle.VerticalAlignment = VerticalAlignment.Center;
headerStyle.FillForegroundColor = IndexedColors.Grey25Percent.Index;
headerStyle.FillPattern = FillPattern.SolidForeground;
Expand All @@ -63,44 +71,50 @@ public SheetBuilder<TSource> UseHeaderStyle(CellStyleOptions cellStyle)

public ISheet Build()
{
_sheet = _workBook.CreateSheet(_options?.Name ?? "Sheet 1");
_sheet = _workBook.CreateSheet(_options?.Name ??
new CultureInfo("en-US").TextInfo.ToTitleCase(typeof(TSource).Name));

if (_options.Rtl)
{
_sheet.IsRightToLeft = true;
}
BuildHeader();
BuildHeader(freez: true);
SetData();
SetAutoWidthColumns();
return _sheet;
}

private void SetAutoWidthColumns()
{
for (var i = 0; i < _sheet.GetRow(0).Cells.Count; i++)
{
_sheet.AutoSizeColumn(i);
}
}

private void SetData()
{
foreach (var item in _data)
for (var i = 0; i < _data.Count; i++)
{
var sheetRow = _sheet.CreateRow(item.Row);
var item = _data.ElementAt(i);
var sheetRow = _sheet.CreateRow(i + 1); // +1 to ignore header
_mapper.Map(item.Source, sheetRow);
}

var columnCount = _mapper.Mappings.Count();
for (var i = 0; i < columnCount; i++)
{
_sheet.AutoSizeColumn(i);
GC.Collect();
}
}

private void BuildHeader()
private void BuildHeader(bool freez = false)
{
var headerRow = _sheet.CreateRow(0);
_mapper.MapHeader(ref headerRow);
((SXSSFSheet)_sheet).TrackAllColumnsForAutoSizing();
foreach (var cell in _sheet.GetRow(0))
{
cell.CellStyle = _options.HeaderStyle;
}
}

if (freez)
{
_sheet.CreateFreezePane(0, 1, 0, 1);
}
}
}
}
Loading

0 comments on commit 506a404

Please sign in to comment.