我有以下Linq to Objects查询:
var query = this._vaporizerData
.Where(row => row.Coater == coater)
.Where(row => row.Distributor == distributor)
.Where(row => row.PowerTubeA.HasValue);
if (query.Any())
{
tubeA = query
.Where(row => row.CoaterTime.Value >= readTime.AddMinutes(-5))
.Where(row => row.CoaterTime.Value <= readTime)
.OrderByDescending(row => row.CoaterTime)
.Select(row => row.PowerTubeA)
.First()
.Value;
}
我知道当执行query.Any()行时,会评估第一个Linq查询。我的问题是这个。假设第一个查询的结果是5行数据。当我执行第二个查询(以'tubeA = query'开头)时,我是否更正它会仅针对第一个查询返回的五行进行评估?
非常感谢。
答案 0 :(得分:5)
好吧,有点儿。它根据需要进行评估。因此,如果我知道当执行query.Any()行时,会评估第一个Linq查询。
_vaporizerData
中有一百万行,但第一行与过滤器匹配,则不会迭代其余数据。
当我执行第二个查询(以'tubeA = query'开头)时,我是否更正它会仅针对第一个查询返回的五行进行评估?
是的,但是必须再次找到这些行,针对第一次不匹配的所有行检查过滤器。同样,如果_vaporizerData
中有一百万行,但这次只有 last 行与原始查询匹配,您最终将再次检查所有999,999个不匹配的行。
此外,如果其他任何内容更改了_vaporizerData
之间的内容与Any()
之间的调用,那么的更改将会显示为它确实会回到原始数据源。
最好只执行一次查询,例如
First()
编辑:评论中提到了两个重点:
var minTime = readTime.AddMinutes(-5); // Avoid recalculation
var result = this._vaporizerData
.Where(row => row.Coater == coater)
.Where(row => row.Distributor == distributor)
.Where(row => row.PowerTubeA.HasValue);
.Where(row => row.CoaterTime.Value >= minTime)
.Where(row => row.CoaterTime.Value <= readTime)
.OrderByDescending(row => row.CoaterTime)
.Select(row => row.PowerTubeA)
.FirstOrDefault();
if (result != null)
{
tubeA = result.Value;
}
为空。这对您来说可能是也可能不是问题。result
而非使用.MaxBy(row => row.CoaterTime)
和OrderByDescending
来提高效率。 IIRC,虽然在空输入时会失败,所以只有当你使用First
的原始版本而不是上面的版本时才应该这样做。答案 1 :(得分:1)
让我们想象一下这个集合是一个列表。让我们想象它们是否符合前三个标准是:
F, T, F, F, F, T, F, F, F, T, F, F, T, F, T, F, F, F
(T =匹配,F =不匹配)
对Any
的调用将检查两个元素。那时它知道至少有一个项目。它不会检查更多元素,但返回true。
让我们说那些与其他谓词相匹配的是:
F, F, F, F, F, F, F, F, F, F, F, F, T, F, T, F, F, F
因为我们有一个OrderByDescending
,所以必须检查每一个项目,以产生它的结果。没有其他方法可以知道哪个是第一个。
如果没有,它将检查13,将其视为“第一”,并完成。
一方面,这种一般情况可以是ToList()
可以使事情变得更快的情况 - 因为我们重用查询结果,而不仅仅是重用查询,存储中间结果的好处可能超过成本创建列表。
另一方面,查询的其他重用正好需要这种行为。
答案 2 :(得分:0)
第二个查询不使用第一个查询的结果。
所以你用两个查询来击中对象。 .Any()
为1,.First()
如果您希望重复使用第一个查询的结果而不再次点击该对象,请使用ToList()
,如下所示:
var query = this._vaporizerData
.Where(row => row.Coater == coater)
.Where(row => row.Distributor == distributor)
.Where(row => row.PowerTubeA.HasValue).ToList();
这会将第一个查询结果存储在query
中,其他明智的query
不会保存任何值,但实际上是一个进行查询的语句。
答案 3 :(得分:0)
如果你的基本集合有更多的对象而不是你的查询将返回的对象,你可能不应该调用Any
,因为,正如你所怀疑的那样,它很可能导致许多这些对象被评估两次第一套标准。而是通过调用ToList
或ToArray
:
var interimResults = this._vaporizerData
.Where(row => row.Coater == coater)
.Where(row => row.Distributor == distributor)
.Where(row => row.PowerTubeA.HasValue)
.ToList();
if (interimResults.Count > 0)
{
tubeA = interimResults
.Where(row => row.CoaterTime.Value >= readTime.AddMinutes(-5))
.Where(row => row.CoaterTime.Value <= readTime)
.OrderByDescending(row => row.CoaterTime)
.Select(row => row.PowerTubeA)
.First()
.Value;
}