Запрос сущности с помощью LINQ с использованием имени поля Dyanmic - PullRequest
2 голосов
/ 12 августа 2010

Я создал экран динамического поиска в ASP.NET MVC. Я получил имена полей от объекта посредством отражения, чтобы позволить пользователю выбирать, какие поля он хочет искать, вместо отображения всех полей в представлении.

Когда результат поиска отправляется обратно в контроллер, я получаю FormCollection, содержащую FieldName и значение. Я не знаю, сколько полей ищется, и FormCollection содержит только те поля, которые были выбраны пользователем.

Я хочу иметь возможность теперь взять это имя поля и применить его к моему оператору LINQ, когда я запрашиваю базу данных, например:

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    List<People> searchResults = new List<People>();

    foreach (string key in fieldValueDictionary.Keys)
    {
         searchResults.Add(entities.People.Where(p => p.<use the key string as the fieldName> == fieldValueDictionary[key]));
    }

    return searchResults;
}

Там, где я "использую строку ключа в качестве fieldName", это будет выглядеть как p => p.FirstName == fieldValueDictionary [key] где key = "FirstName". Я пытался и не смог использовать деревья лямбда-выражений, и добился небольшого успеха с Dynamic LINQ. Единственная альтернатива - сделать что-то вроде:

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    IQueryable<People> results = entities.People;

    foreach (string key in fieldValueDictionary.Keys)
    {
         switch (k)
         {
             case "FirstName": results = results.Where(entities.People.Where(p => p.FirstName == k);
             case "LastName": results = results.Where(entities.People.Where(p => p.LastName == k);
             // Repeat for all 26 fields in table
         }
    }

    return results.ToList<People>();
}

ОБНОВЛЕНИЕ : Я провел исследование деревьев лямбда-выражений в следующих статьях:

динамическое создание лямбда-выражений + linq + OrderByDescending

Проблема параметров с Expression.Lambda ()

LINQ: передача лямбда-выражения в качестве параметра, который должен быть выполнен и возвращен методом

Я получил лямбду для вывода следующего: "p => p.FirstName", но я не могу заставить это работать где-то. Какие-либо предложения? Мой код ниже:

MemberInfo member = typeof(People).GetProperty("FirstName");
ParameterExpression cParam = Expression.Parameter(typeof(People), "p");    
Expression body = Expression.MakeMemberAccess(cParam, member);        

var lambda = Expression.Lambda(body, cParam);

Ответы [ 3 ]

7 голосов
/ 12 августа 2010

После гораздо большего количества проб и ошибок и поиска я случайно нашел еще одну публикацию SO, посвященную той же проблеме:

InvalidOperationException: нет метода 'Where' для типа 'System.Linq.Queryable'совместим с предоставленными аргументами

Вот мой модифицированный код, который работает:

        IQueryable query = entities.People;
        Type[] exprArgTypes = { query.ElementType };

        string propToWhere = "FirstName";            

        ParameterExpression p = Expression.Parameter(typeof(People), "p");
        MemberExpression member = Expression.PropertyOrField(p, propToWhere);
        LambdaExpression lambda = Expression.Lambda<Func<People, bool>>(Expression.Equal(member, Expression.Constant("Scott")), p);                            

        MethodCallExpression methodCall = Expression.Call(typeof(Queryable), "Where", exprArgTypes, query.Expression, lambda);

        IQueryable q = query.Provider.CreateQuery(methodCall);

С некоторыми, надеюсь, довольно легкими изменениями, я смогу заставить это работать с любым типом.

Еще раз спасибо за ваши ответы Ани и Джон Боуэн

5 голосов
/ 12 августа 2010

Вы пытались получить значение из PropertyInfo?

entities.People.Where(p => (p.GetType().GetProperty(key).GetValue(p, null) as string) == fieldValueDictionary[key])
1 голос
/ 12 августа 2010
  public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
        {
            return !fieldValueDictionary.Any()
                   ? entities.People 
                   : entities.People.Where(p => fieldValueDictionary.All(kvp => PropertyStringEquals(p, kvp.Key, kvp.Value)))
                                    .ToList();
        }

  private bool PropertyStringEquals(object obj, string propertyName, string comparison)
        {
            var val = obj.GetType().GetProperty(propertyName).GetValue(obj, null);
            return val == null ? comparison == null : val.ToString() == comparison; ;
        }
...