Skip to content

Commit

Permalink
LoadFromCollection - support for Dictionary properties (#1176)
Browse files Browse the repository at this point in the history
* #969, #1058 - implemented EPPlusDictionaryColumnAttribute for LoadFromCollection with attributes

* #969, #1058 - added support for Dictionary property in LoadFromCollection

* #1058, #969 - LoadFromCollection, support for Dictionary property

* #1058, #969 - added testclass

* #1058, #969 - added unit test for reading column headers/keys from attribute
  • Loading branch information
swmal committed Nov 22, 2023
1 parent 945b83e commit a5574ee
Show file tree
Hide file tree
Showing 8 changed files with 566 additions and 140 deletions.
47 changes: 47 additions & 0 deletions src/EPPlus/Attributes/EPPlusDictionaryColumnAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*************************************************************************************************
Required Notice: Copyright (C) EPPlus Software AB.
This software is licensed under PolyForm Noncommercial License 1.0.0
and may only be used for noncommercial purposes
https://polyformproject.org/licenses/noncommercial/1.0.0/
A commercial license to use this software can be purchased at https://epplussoftware.com
*************************************************************************************************
Date Author Change
*************************************************************************************************
7/11/2023 EPPlus Software AB EPPlus 7
*************************************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OfficeOpenXml.Attributes
{
/// <summary>
/// This attributes can only be used on properties that are of the type IDictionary&lt;string, string&gt;.
/// Columns will be added based on the items in <see cref="EPPlusDictionaryColumnAttribute.ColumnHeaders"/>
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field)]
internal class EPPlusDictionaryColumnAttribute : Attribute
{
/// <summary>
/// Order of the columns value, default value is 0
/// </summary>
public int Order
{
get;
set;
}

/// <summary>
/// The values of this array will be used to generate columns (one column for each item).
/// </summary>
public string[] ColumnHeaders { get; set; }

/// <summary>
/// Should be unique within all attributes. Will be used to retrieve the keys of the Dictionary
/// that also will be used to create the columns for this property.
/// </summary>
public string KeyId { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Engineering
[FunctionMetadata(
Category = ExcelFunctionCategory.Engineering,
EPPlusVersion = "5.1",
Description = "Calculates the modified Bessel function Yn(x)")]
Description = "Converts a number from one measurement system to another")]
public class ConvertFunction : ExcelFunction
{
public override int ArgumentMinLength => 3;
Expand Down
4 changes: 4 additions & 0 deletions src/EPPlus/LoadFunctions/ColumnInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public ColumnInfo()

public int SortOrder { get; set; }

public bool IsDictionaryProperty { get; set; }

public string DictinaryKey { get; set; }

public List<int> SortOrderLevels { get; set; }
public int Index { get; set; }

Expand Down
32 changes: 29 additions & 3 deletions src/EPPlus/LoadFunctions/LoadFromCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public LoadFromCollection(ExcelRangeBase range, IEnumerable<T> items, LoadFromCo
LoadFromCollectionColumns<T> cols;
if (parameters.Members == null)
{
cols = new LoadFromCollectionColumns<T>(parameters.BindingFlags, SortOrderProperties);
cols = new LoadFromCollectionColumns<T>(parameters, SortOrderProperties);
var columns = cols.Setup();
_columns = columns.ToArray();
SetHiddenColumns();
Expand All @@ -66,7 +66,7 @@ public LoadFromCollection(ExcelRangeBase range, IEnumerable<T> items, LoadFromCo
{
throw (new ArgumentException("Parameter Members must have at least one property. Length is zero"));
}
cols = new LoadFromCollectionColumns<T>(parameters.BindingFlags, SortOrderProperties, parameters.Members);
cols = new LoadFromCollectionColumns<T>(parameters, SortOrderProperties);
var columns = cols.Setup();
_columns = columns.ToArray();
// the ValidateType method will throw an InvalidCastException
Expand Down Expand Up @@ -228,6 +228,18 @@ private void SetValuesAndFormulas(object[,] values, Dictionary<int, FormulaCell>
{
v = ((MethodInfo)member).Invoke(obj, null);
}
if (colInfo.IsDictionaryProperty)
{
var dict = v as Dictionary<string, object>;
if(dict != null && dict.ContainsKey(colInfo.DictinaryKey))
{
v = dict[colInfo.DictinaryKey];
}
else
{
v = null;
}
}

#if (!NET35)
if (v != null)
Expand Down Expand Up @@ -273,8 +285,9 @@ private object GetValueByPath(object obj, string path)
{
var members = path.Split('.');
object o = obj;
foreach(var member in members)
for(var ix = 0; ix < members.Length; ix++)
{
var member = members[ix];
if (o == null) return null;
var memberInfos = o.GetType().GetMember(member);
if(memberInfos == null || memberInfos.Length == 0)
Expand All @@ -298,6 +311,19 @@ private object GetValueByPath(object obj, string path)
{
throw new NotSupportedException("Invalid member: '" + memberInfo.Name + "', not supported member type '" + memberInfo.GetType().FullName + "'");
}
if(o is Dictionary<string, object> dict && ix < members.Length + 1)
{
var key = members[ix + 1];
if(dict.ContainsKey(key))
{
o = dict[key];
}
else
{
o = null;
}
break;
}
}
return o;
}
Expand Down
Loading

0 comments on commit a5574ee

Please sign in to comment.