Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a LINQ Select expression dynamically from string column names

I have a method which looks something like this:

public string GetColVal(string aAcctField, bool callM1, bool callM2)
{
    if (callM1)
    {
        // create select clause here to select a string column with name
        // equal to the value of aAcctField from Table1
        // Expression<Func<Table1, string>> selector = ?
        return M1(selector);
    }

    if (callM2)
    {
        // create select clause here to select a string column with name
        // equal to the value of aAcctField from Table2
        // Expression<Func<Table2, string>> selector = ?
        return M2(selector);
    }
}

And M1() is something like this:

public string M1(Expression<Func<Table1, string>> columnToSelect, string xType)
{
    // other logic 
    string acct = _cntx.Where(c => c.Type == xType)
                       .Select(columnToSelect)
                       .FirstOrDefault();
    return acct;
}

M2() is also something similar. Please note that the methods are over-simplified. And the methods M1() and M2() work perfectly. I can invoke them this way:

// MyColumn is a strongly typed column in Table1
string acct = M1(x => x.MyColumn, "some value");

But, inside the method GetColVal() how do I construct the select clauses? The comments regarding selector will help you understand what I intend to do. So, please go ahead and read the comment.

I have tried this:

public string GetColVal(string aAcctField, bool callM1, bool callM2)
{
    if (callM1)
    {
        // create select clause here to select a string column with name
        // equal to the value of aAcctField from Table1
        Expression<Func<Table1, string>> selector = (w) => w.GetType().GetProperty(aAcctField).Name;
        return M1(selector);
    }
    ...
}

and I get the exception:

LINQ to Entities does not recognize the method 'System.Reflection.PropertyInfo GetProperty(System.String)' method, and this method cannot be translated into a store expression

I have looked at these:

  • Create dynamic LINQ expression for Select with FirstOrDefault inside
  • Linq access property by variable
  • Get property value from string using reflection in C#
  • and many others.

but none of them is quite something like what I need.

like image 828
Sнаđошƒаӽ Avatar asked Jan 16 '17 12:01

Sнаđошƒаӽ


1 Answers

Basically you need to use the Expression class methods like Expression.Lambda, Expression.PropertyOrField etc. to build the desired selector like:

static Expression<Func<T, TValue>> MemberSelector<T, TValue>(string name)
{
    var parameter = Expression.Parameter(typeof(T), "item");
    var body = Expression.PropertyOrField(parameter, name);
    return Expression.Lambda<Func<T, TValue>>(body, parameter);
}

To support nested properties, change var body = ... line to

var body = name.Split('.').Aggregate((Expression)parameter, Expression.PropertyOrField);

Sample usage:

if (callM1)
{
    return M1(MemberSelector<Table1, string>(aAcctField));
}
...
like image 118
Ivan Stoev Avatar answered Sep 30 '22 11:09

Ivan Stoev