Как я могу использовать 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/и каким-то образом достигнуть того же эффекта?
Ответы
Ответ 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:
Возможным решением является создание выражений программным путем. Как использовать деревья выражений для создания динамических запросов