ExcelMapper icon indicating copy to clipboard operation
ExcelMapper copied to clipboard

Q: Nested property expressions support

Open vladimir-ilnytskyi opened this issue 1 year ago • 1 comments

Hi!

I'm facing an issue with nested object mapping from excel:

class Address { 
public string City {get ;set;}
 ...
 }

class Product {
public Address ShippingAddress { get; set; }
public Address DeliveryAddress {get; set; }
}

It would be nice to be able to use mappings for shipping address city and Delivery address city like this:

mapper.AddMapping<Product>("shipping address city", x => x.ShippingAddress.City); // handle expression with nested property accessors. For sure it is possible to use refrection on nested objects So now i get "something like cannot convert cell string to type string".

Something like this would help

public static (PropertyInfo propertyInfo, string fullPath) GetPropertyInfo<T>(Expression<Func<T, object>> propertySelector)
    {
        if (propertySelector is not LambdaExpression lambdaExpression)
        {
            throw new ArgumentException($"Unsupported property selector: {propertySelector}", nameof(propertySelector));
        }

        var pathBuilder = new StringBuilder();
        var body = lambdaExpression.Body;

        while (body is MemberExpression or UnaryExpression{ Operand: MemberExpression })
        {
            var memberAccess = body as MemberExpression ?? (MemberExpression)((UnaryExpression)body).Operand;

            if (pathBuilder.Length > 0)
            {
                pathBuilder.Insert(0, ".");
            }

            pathBuilder.Insert(0, memberAccess.Member.Name);
            body = memberAccess.Expression;
        }

        if (pathBuilder.Length > 0)
        {
            pathBuilder.Insert(0, typeof(T).Name + ".");
        }

        var lambdaBody = lambdaExpression.Body.NodeType == ExpressionType.MemberAccess ?
            (MemberExpression)lambdaExpression.Body :
            (MemberExpression)((UnaryExpression)lambdaExpression.Body).Operand; // for nullable value such as int?

        // body.Member will return the MemberInfo of the base class, so we have to get it from T...
        //return (PropertyInfo)body.Member;

        var propertyInfo = lambdaBody.Expression.Type.GetProperty(lambdaBody.Member.Name);
        return (propertyInfo, pathBuilder.ToString());
    }

Having separate mapping for type is making impossible to map different properties of same type to excel, maybe there is a way but i seems like i have stuck with using custom mapping funcs.

Please advise,

Best regards

vladimir-ilnytskyi avatar Oct 16 '24 11:10 vladimir-ilnytskyi

Thanks a lot for mapping out a solution already! Could you make a PR?

mganss avatar Oct 28 '24 11:10 mganss