Получение атрибута внутри Linq «Where» с использованием строки

#c# #asp.net #entity-framework #linq #lambda

#c# #asp.net #entity-framework #linq #лямбда

Вопрос:

Я пытаюсь передать список строк, содержащих поля, которые необходимо отфильтровать.

 string[] filterList = {"CostCenterId", "Description", ....}
  

Определение объекта:

 public class CostCenter
{
    public int Id { get; set; }
    public string CostCenterId { get; set; }
    public string Description { get; set; }
}
  

Вместо того, чтобы делать:

 var filterData = data
  .Where(x => x.CostCenterId.Contains(request.Filter) || x.Description.Contains(request.Filter));
  

Возможно ли получить атрибут внутри лямбда-выражения: Where() передав string вместо этого a?

Возможно ли сделать что-то вроде:

 var filterData = data
  .Where(x => x["CostCenterId"].Contains(request.Filter) || x.["Desription"]
  .Contains(request.Filter));
  

замена значений из списка фильтров:

 var filterData = data
  .Where(x => x[filterList[0]].Contains(request.Filter) || x.[filterList[1]
  .Contains(request.Filter));
  

Я попробовал следующий подход:

 var filterData = data
  .Where(x => x.GetType().GetField("CostCenterId").Name.Contains(filter) || x.GetType().GetField("Description").Name.Contains(filter));
  

но это не работает,

Ожидаемый результат — отфильтрованные данные. Результат, который я получаю прямо сейчас, равен нулю, любая помощь будет с благодарностью

Комментарии:

1. «это не работает» мало что говорит. Является ли это запросом EF / other ORM? Какую ошибку / неожиданный результат вы получаете?

2. Мои извинения, я забыл упомянуть в своем вопросе, что это запрос EF. Ожидаемый результат — отфильтрованные данные. Результат, который я получаю прямо сейчас, равен нулю.

3. Используйте DynamicLinq , если только вы не делаете это для создания некоторой абстракции поверх EF, например, вы пытаетесь создать QueryTableWhere("tablename", "columnname1", "value1", "columnname2", "value2") метод общего типа — в этом случае не беспокойтесь.. В конечном итоге это только сбивает вас с толку, усложняя задачу с каждым поворотом, чем просто написание прямого запроса LINQ в первую очередь

Ответ №1:

EF использует IQueryable интерфейс, который принимает деревья выражений, чтобы он мог анализировать ваш код и пытаться перевести его в реальный SQL. Один из вариантов здесь — самостоятельно создать выражение фильтра для Where предложения. Для ограниченного случая обработки только строковых свойств вы можете сделать что-то подобное (крайний случай пустого filterList опущен):

 var filterValue = "test";// request.Filter

string[] filterList = { "CostCenterId", "Description" };
var par = Expression.Parameter(typeof(CostCenter));
var stringContains = typeof(string).GetMethod(nameof(string.Contains), new[] {typeof(string)});
var predicate = filterList
    .Select(f => 
    {
        var prop = Expression.Property(par, typeof(CostCenter), f);
        return (Expression) Expression.Call(prop, stringContains, Expression.Constant(filterValue));
    })
    .Aggregate((agg,curr) => Expression.OrElse(agg,curr));
    
var filter = Expression.Lambda<Func<CostCenter, bool>>(predicate, par);
  

А затем использовать его в запросе:

 var filterData = data.Where(filter);
  

Комментарии:

1. Спасибо за это. Я пытался реализовать это решение, но, похоже, получаю следующую ошибку: `’IEnumerable<CostCenter>’ не содержит определения для ‘Where’, а лучший метод расширения перегружает ‘Запрашиваемый. Где<CostCenter>(IQueryable<CostCenter>, выражение<Func<CostCenter, bool>>)’ требуется приемник типа ‘IQueryable<CostCenter>’ ` Это происходит, когда я передаю выражение фильтра в данные. Где()

2. @ezennnn что это за тип data ?

3. Тип data IQueryable<CostCenter>

4. Оказывается, ошибка заключалась в том, что я изменил IQueryable<CostCenter> на IEnumerable<CostCenter>, изменив его на тип IQueryable, решил проблему. Спасибо

5. @ezennnn Рад, что это помогло. Да, хотел написать, что из-за вашей ошибки ваш тип не IQueryable соответствует =).