Подтвердить что ты не робот

Как я могу использовать Predicate <T> в предложении EF Where()?

Я пытаюсь использовать предикаты в своем коде фильтрации EF.

Это работает:

IQueryable<Customer> filtered = customers.Where(x => x.HasMoney && x.WantsProduct);

Но это:

Predicate<T> hasMoney = x => x.HasMoney;
Predicate<T> wantsProduct = x => x.WantsProduct;
IQueryable<Customer> filtered = customers.Where(x => hasMoney(x) && wantsProduct(x));

не работает во время выполнения:

The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.

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

Как я могу заставить провайдера EF Linq "понять" мой предикат (ы)?

Я получаю тот же результат, если я использую Func<T, bool>. Он работает с Expression<Func<T>>, но я не могу комбинировать выражения для сложной фильтрации. Я предпочитаю избегать внешних библиотек, если это возможно.

UPDATE:
Если этого не может быть сделано, какие у меня варианты? Возможно, выражения должны быть объединены/or'ed/и каким-то образом достигнуть того же эффекта?

4b9b3361

Ответ 1

Expression<Func<Customer, bool>> hasMoney = x => x.HasMoney;
Expression<Func<Customer, bool>> wantsProduct = x => x.WantsProduct;
IQueryable<Customer> filtered = customers.Where(hasMoney).Where(wantsProduct);
  • Используйте Expression<T>, чтобы оставить x => x.HasMoney в качестве дерева выражений, а не компилировать его в .NET-метод.
  • Используйте Expression<Func<Customer, bool>>, а не Expression<Predicate<Customer>>, потому что то, что Queryable.Where ожидает
  • Передайте его непосредственно в .Where, объединив их с помощью нескольких вызовов .Where вместо &&.

Можно получить более сложные условия (в том числе и не, и т.д.), работая путем их перезаписи с помощью .Union, .Except и т.д.

Альтернативой является использование LINQKit AsExpandable:

Expression<Func<Customer, bool>> hasMoney = x => x.HasMoney;
Expression<Func<Customer, bool>> wantsProduct = x => x.WantsProduct;
IQueryable<Customer> filtered = customers.AsExpandable().Where(x => hasMoney.Invoke(x) && wantsProduct.Invoke(x));

Ответ 2

К сожалению, нет способа использовать Predicate<T> в EF linq, так как невозможно сопоставить его в SQL-запросе. Это можно сделать с помощью выражений только потому, что их можно разобрать и преобразовать в SQL.

На самом деле есть 4 языка, которые сделали linq возможным:

  • Методы расширения
  • Тип вывода
  • Затворы
    и для linq2sql особенно
  • Выражения

UPDATE:
Возможным решением является создание выражений программным путем. Как использовать деревья выражений для создания динамических запросов