2

我有一个用于查询数据库的 EF Code First Db 上下文。当从我的聚合存储库中以 s 的形式传递查询时,我注意到一些性能问题,Func<Product, bool>并且在进一步调查时发现查询没有被转换为 SQL 查询。

经过一番挖掘,我发现了以下内容。

var results = _context.Products
            .Where(p => p.ProductCode.Contains("AAA"))
            .Where(p => p.CategoryId == 1)
            .ToList();

这完全符合预期。它生成一些带有 Where 子句的参数化 SQL。

==================================================== =================

var results2 = _context.Products
            .Where(p => p.ProductCode.Contains("AAA") && p.CategoryId == 1)
            .ToList();

这也按预期工作。它生成与上面相同的sql

==================================================== =================

Func<Product, bool> pred = (p => p.ProductCode.Contains("AAA") && p.CategoryId == 1);

var results3 = _context.Products.Where(pred).ToList();

这是坏了。它不会在 SQL 中生成 where 子句,而是返回所有内容,然后在代码中对其进行过滤。

4

3 回答 3

5

因为为了翻译成SQL,它必须是一个Expression<...>,而不是一个Func<...>

这是由编译器自动为您完成的,并且由于 Linq-to-SQL 类上的重载采用表达式,而不是委托,编译器会自动将您的代码(看起来像 lambda 或匿名方法)转换为表达式对象并通过。

但是,如果您自己负责构建函数,编译器就无法做到这一点,而且 Linq-to-SQL 不采用匿名方法,它只采用表达式。

您可以做的是执行您可以执行的查询部分,然后通过您的函数过滤结果,但我会考虑将您的值的类型改为表达式。

于 2011-10-16T10:17:58.880 回答
1

Where()在我发布此 ReSharper 后不久,它就通过向我展示了扩展方法的重载方法签名来帮助回答了我的问题。

它需要Func<T, bool>Expression<Func<T, bool>>。如果您在外部声明谓词,则必须使用 Expression 变体,因为前者不会翻译成 sql。

于 2011-10-16T10:16:59.257 回答
0

这就是查询读取整个表的原因。

Func使用 a 而不是 a 时Expression,编译器会选择 on-System.Linq.Enumerable而不是 的方法System.Linq.QueryableEnumerable方法迭代源集合(有时是惰性的),而方法Queryable构建表达式树。

由于调用Where不是表达式树的一部分,因此 sql 生成器在查询翻译期间看不到它。

于 2011-10-16T11:49:50.230 回答