我有一个带有过滤lambda表达式的实体框架应用程序,如下所示:
x => x.Where(pn => pn.Product.Evaluation.Any(ee => ee.EvaluationToDocuments.Any(e2d => e2d.Document.SpiderFailedCheckCount != null)))
事实证明这是非常缓慢的,反过来要快得多,即找到正确的EvaluationToDocuments,并通过评估选择他们的产品。
所以我做了一个预先计算:
spiderFailedCheckCountProductIds = _context.EvaluationToDocuments.Where(e2d => e2d.Document.SpiderFailedCheckCount != null).Select(e2d => e2d.Evaluation.ProductID).Distinct().OrderBy(p => p).ToList();
然后我的第一个表达式可以这样做:
x => x.Where(pn => spiderFailedCheckCountProductIds.Contains(pn.ProductID))
它可能更快,但速度足够快,比第一个版本快很多。
一般来说,函数中局部变量的目的是避免多次进行昂贵的计算。这可以用lambda表达式完成吗?类似于(x) => var a = x+5, a*4
(不是最好的例子)
我想避免编写普通函数,并将这些过滤函数保留为对象。
答案 0 :(得分:1)
有let clause(来自MSDN的示例):
var earlyBirdQuery =
from sentence in strings
let words = sentence.Split(' ')
from word in words
let w = word.ToLower()
where w[0] == 'a' || w[0] == 'e'
|| w[0] == 'i' || w[0] == 'o'
|| w[0] == 'u'
select word;
但请注意,您的问题是另一个问题:查询生成的SQL查询计划非常糟糕。您通过对SQL执行两个单独的查询来解决这个问题。也许您甚至可以将两个查询合并在一起并在单个"批处理"中进行。
SQL Server通常已经缓存了相同的子表达式。如果你在查询中执行MAX(某事)的两倍,那么SQL不可能执行两次。它会注意到它可以重用结果并重用它。
SELECT MAX(id), MAX(id) FROM Foo
或者如果你这样做
SELECT SUBSTRING(name, 1, 5) FROM Foo WHERE SUBSTRING(name, 1, 5) = 'Hello'
可能SUBSTRING
每行只构建一次。