9

我正在使用 Microsoft 的实体框架作为 ORM,并且想知道如何解决以下问题。我想ProductProducts集合中获取一些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 解析器对这两种格式的处理方式如此不同?
  • 我可以做些什么来利用过滤器分开但在服务器上执行它?
4

3 回答 3

8

您需要使用 anExpression<Func<Product, bool>>才能使其按预期工作。一个plainFunc<Product, bool>告诉LINQ 你希望它Where在你的程序中运行MSIL,而不是SQL。这就是 SQL 拉入整个表的原因,然后您的 .NET 代码在整个表上运行谓词。

于 2012-01-23T08:55:36.283 回答
4

您正在返回一个Func,但要将谓词注入 SQL,LINQ 需要一个表达式树。如果您将方法(当然还有局部变量)的返回类型更改为Expression<Func<Product, bool>>.

于 2012-01-23T08:58:02.467 回答
2

因为在第二种情况下 filter func 可能任意 LINQ to EF 无法将您的过滤器解析为 SQL 并且必须在客户端解决它。

于 2012-01-23T08:56:35.820 回答