2017-01-16 2 views
2

У меня есть метод, который выглядит примерно так:Создание выражения LINQ Выбор динамически из названий строк столбцов

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); 
    } 
} 

И M1() это что-то вроде этого:

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() также что-то подобное. Обратите внимание, что методы упрощены. И методы M1() и M2() работают отлично. Я могу вызвать их таким образом:

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

Но внутри метода GetColVal() как я построить выберите пункты? Комментарии, касающиеся selector, помогут вам понять, что я намереваюсь сделать. Итак, пожалуйста, прочитайте комментарий.

Я попытался это:

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); 
    } 
    ... 
} 

и я получаю исключение:

LINQ к Entities не распознает метод 'System.Reflection.PropertyInfo GetProperty (System.String)' метод, и этот метод не может быть переведен в выражение магазина

Я рассмотрел это:

но ни один из них не является чем-то вроде того, что мне нужно.

ответ

7

В основном вам нужно использовать методы Expression класса как Expression.Lambda, Expression.PropertyOrField и т.д., чтобы создать нужный селектор, как:

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); 
} 

Для поддержки вложенных свойств, изменить var body = ... строку

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

Sample использование:

if (callM1) 
{ 
    return M1(MemberSelector<Table1, string>(aAcctField)); 
} 
... 
+0

Является ли 'MemberSelector' методом расширения? Если нет (и я думаю, что это не так), что это такое и где его разместить? Извините, если это глупый вопрос. –

+1

Нет проблем. Вы можете поместить его в тот же класс, где вам нужно его вызвать. Или в отдельном статическом классе, например внутри 'public static class ExpressionUtils' (добавьте модификатор' public' к методу) и используйте 'ExpressionUtils.MemberSelector' или если вы находитесь на C# 6, поместите' using static SomeNamespace.ExpressionUtils; ' и продолжайте называть его просто «MemberSelector». –

+1

Прекрасно работает! Мне придется потратить некоторое время на это, хотя, чтобы усвоить все это :-) –