2014-10-07 1 views
4

Оказывается вернуть IEnumerable, а не IQueryable:Возможно ли вернуть IQueryable <> обратно из набора EF при применении предиката?

метод параметра: Func<Cat, bool> predicate

код:

var allCats = _catEntities.GetCats(); // IQueryable 

if (skip.HasValue) allCats = allCats .Skip(skip.Value); 
if (take.HasValue) allCats = allCats .Take(take.Value); 

if (predicate != null) 
      { 
       allCats = allCats.Where(predicate); 
      } 

Это не компилируется, потому что .Where возвращается IEnumerable вместо IQueryable. Я знаю, что могу делать .AsQueryable или что-то еще, но я подозреваю, что это не будет относиться к нему как к правильному IQueryable.

Есть ли это простое исправление?

ответ

2

Проблема заключается в том, что Func<Cat, bool> уже скомпилирован как .NET-код, и поэтому он не может быть выполнен за пределами процесса .NET.

Итак, чтобы применить предикат к allCats, запрос, заданный allCats, в это время должен быть выполнен. Используя AsQueryable, вы, как вы догадались, оберните только возвращаемое перечисление IEnumerable.

Если вы хотите, чтобы предикат был переведен и выполнен поставщиком LINQ, вы можете использовать Expression<Func<Cat, bool>>. Обратите внимание, что это введет связь между реализацией IQueryable и определением предиката. (Потому что предикат должен быть чем-то, что может быть выполнено поставщиком LINQ).

Использование лямбда-выражение, можно определить Expression<Func<Cat, bool>> довольно просто:

Expression<Func<Cat, bool>> predicateExpression = c => c.Gender == Gender.Male; 
+0

интересная, спасибо. Как он прекомпилирует его, учитывая, что он передан как параметр? Это может быть одна из многих вещей. Исправлено, спасибо. – NibblyPig

+0

Есть два (больших) шага. Компилятор C# преобразует лямбда-выражение в дерево выражений (т. Е. [Абстрактное дерево синтаксиса] (http://en.wikipedia.org/wiki/Abstract_syntax_tree)). Затем поставщик LINQ обрабатывает дерево выражений и преобразует его в форму, которую он может выполнить (в случае EF, код SQL). –

2

Этот параметр predicate должен быть Expression<Func<Cat, bool>>, а не только Func<Cat, bool>.

Таким образом, вы будет получить IQueryable обратно, потому что вы будете использовать Queryable.Where вместо Enumerable.Where.

Вы все еще можете использовать выражение лямбда при вызове метода: компилятор знает, как перевести лямбду в выражение.