Search code examples
c#entity-frameworkreflection.net-coreexpression-trees

Auto Column Mapping Using Reflection and expression


is that possible to automate these mappings with reflection?

i have a simple column mapping :

var columnsMap = new Dictionary<string, Expression<Func<Industry, object>>>
{
    ["id"] = v => v.Id,
    ["name"] = v => v.Name,
    ["isActive"] = v => v.IsActive
};

columnsMap run-time result:

enter image description here


i want to automate these mappings in a wrapper class:

 public class QueryColumnMapper<T> : Dictionary<string, Expression<Func<T, object>>>
    {
        public QueryColumnMapper<T> GenerateMappings()
        {
            foreach (var item in typeof(T).GetProperties())
            {
                // get dictionary key ======> its OK
                var name = Char.ToLowerInvariant(item.Name[0]) + item.Name.Substring(1); //camel-case name

                // get expression    =======> this is the problem. wrong way
                Expression<Func<T, object>> exp = v => v.GetType().GetProperty(item.Name);
                //Expression<Func<T, object>> exp = v => v.?????;    <-----   

                // add to mapper object
                this.Add(name, exp);
            }
            return this;
        }
    }

example of using this class:

var columnsMap = new QueryColumnMapper<Industry>().GenerateMappings();  

columnsMap run-time result: enter image description here

i don't know is that possible to get my expression dynamically in run-time?

( i'm using this mapping dictionary for apply filtering on entity-framework IQueryable query. with first example (manual mapping) its working but i don't know how to do that in run-time without manual mapping )


Solution

  • You can build a custom expression manually using the property name

    // x =>
    var parameter = Expression.Parameter(typeof(T));
    // x.Name
    var mapProperty = Expression.Property(parameter, "Name");
    // (object)x.Name
    var convertedExpression = Expression.Convert(mapProperty, typeof(object));
    // x => (object)x.Name
    var exp = Expression.Lambda<Func<T, object>>(convertedExpression, parameter);
    

    If this is a common subset and you find you're doing it quite often you can create a base interface.