Почему анализатор LINQ EntityFramework по-разному обрабатывает внешний предикат? - PullRequest
9 голосов
/ 23 января 2012

Я использую Entity Framework от Microsoft в качестве ORM, и мне интересно, как решить следующую проблему. Я хочу получить количество Product объектов из коллекции Products, где Product.StartDate больше, чем сегодня. (Это упрощенная версия всей проблемы.)

Я сейчас использую:

var query = dbContext.Products.Where(p => p.StartDate > DateTime.Now);

Когда это выполняется, после использования ToList(), например, для запроса, он работает, и созданный SQL эффективно:

SELECT * FROM Product WHERE StartDate > (GetDate());

Однако я хочу переместить предикат в функцию для лучшей управляемости, поэтому я попробовал это:

private Func<Product, bool> GetFilter()
{
  Func<Product, bool> filter = p => p.StartDate > DateTime.Now;
  return filter;
}
var query = dbContext.Products.Where(GetFilter());

Это также работает с точки зрения кода, поскольку возвращает тот же набор Product, но на этот раз созданный SQL аналогичен:

SELECT * FROM Product;

Фильтр перемещен с SQL Server на клиент, что делает его гораздо менее эффективным.

Итак, мои вопросы:

  • Почему это происходит, почему анализатор LINQ так по-разному относится к этим двум форматам?
  • Что я могу сделать, чтобы использовать фильтр отдельно, но при его запуске на сервере?

Ответы [ 3 ]

8 голосов
/ 23 января 2012

Вам нужно использовать Expression<Func<Product, bool>>, чтобы он работал так, как вы собираетесь.Простой Func<Product, bool> говорит LINQ, что вы хотите, чтобы он запускал Where в MSIL в вашей программе, а не в SQL.Вот почему SQL вытягивает всю таблицу, а ваш код .NET выполняет предикат для всей таблицы.

4 голосов
/ 23 января 2012

Вы возвращаете Func, но для внедрения предиката в SQL LINQ требуется дерево выражений. Это должно работать, если вы измените тип возврата вашего метода (и вашей локальной переменной, конечно) на Expression<Func<Product, bool>>.

2 голосов
/ 23 января 2012

Так как во втором случае фильтр func может быть произвольным LINQ to EF не может проанализировать ваш фильтр в SQL и должен разрешить его на стороне клиента.

...