如何在条件语句中使用Linq's . count()方法
本文关键字:count 方法 Linq 条件 语句 | 更新日期: 2023-09-27 17:51:17
我有一个线程,定期检查我的MS SQL表中的任何记录,他们的"Processed"位字段设置为0。然后线程使用这些记录执行一些代码,然后将它们的Processed位设置为1;把它当作一个队列。我用来检索这些记录的Linq查询跨越多行并且相当复杂(原因与问题无关),因此这里是一个非常简化的版本:
var RecordsToProcess = MyTable.Where(i => i.Processed == 0); // Very simplified
在继续之前,我需要等待所有的记录都被处理,所以我想使用这样的东西:
while (RecordsToProcess.Count() > 0)
{
System.Threading.Thread.Sleep(1000);
}
问题是,虽然线程实际上处理记录并将其Processed位设置为1,但条件语句中的RecordsToProcess.Count()的值永远不会减少,因此我们得到一个无限循环。我的猜测是,调用. count()将该整数存储在内存中,然后循环的每次迭代都查看该值,而不是查询数据库以获得当前计数。我可以通过将查询移动到条件语句中来获得我想要的行为,如下所示:
while (true)
{
if (MyTable.Where(i => i.Processed == 0).Count() > 0)
System.Threading.Thread.Sleep(1000);
else
break;
}
由于我实际使用的查询比这个例子中的查询复杂得多,因此这样做会使其难以阅读。是否有一些我可以使用,这是类似于RecordsToProcess.Count()> 0,但查询数据库的每次迭代,而不是使用存储在内存中的初始计数(假设我是正确的)?
注意:我通常不会使用这样一个有潜在危险的while循环,但我只需要运行这个页面最多4或5次,然后再也不运行了。所以我不太担心。根据评论编辑原文
我认为部分问题在于编译器如何优化循环。
很可能是您的查询中的某些内容正在缓存数据。如果整个查询使用延迟求值,除了在循环中检查Count
外,每次在查询中调用Count
时,它都会被重新求值。在第二个示例中,整个查询都在循环中,因此每次都必须重新求值,而不管它是否实际上使用延迟求值。我会检查MSDN文档中关于您正在使用的操作符的remarks
。
为了性能和清晰度,我还建议在这种情况下使用Any
而不是Count
。根据迭代的内容,Count
通常会遍历集合以查看有多少元素,但Any
更懒惰。在LINQ to Object中,Count()
针对实现ICollection
的序列进行了优化,使用Count
属性,这比迭代快得多,Any()
在找到1个元素后停止检查。正如Erik下面建议的那样,在LINQ to SQL中,可能会有类似TOP 1
的东西添加到SELECT
语句中。我认为SQL有自己的COUNT
优化,但我没有做任何研究。
在适当的时候使用Any()
还可以通过去掉Count() > 0
中的运算符来帮助提高可读性,并且更清楚地表达您对bool
而不是int
感兴趣。
我将这样实现你的方法:
var query = MyTable.Where(i => i.Processed == 0);
while(true) {
if (!query.Any()) break;
Thread.Sleep(1000);
}
或者更好,如果你能让它延迟执行:
var query = MyTable.Where(i => i.Processed == 0);
while(query.Any()) { Thread.Sleep(1000); }
但是,正如其他答案所提到的,更多关于如何构造查询的信息将会有所帮助。
您没有在每个循环上刷新RecordsToProcess变量
While(RecordsToProcess.Count() > 0)
{
System.Threading.Thread.Sleep(1000);
RecordsToProcess = MyTable.Where(i => i.Processed == 0);
}