当结果可能时,IQueryable ToList()首选.Count()吗?

时间:2017-06-13 10:32:31

标签: c# .net

这是一个关于表现的问题。以下是我在自己的代码和同事代码中看到的模式

var items = GetItems();

变量items现在包含一个IQueryable,它将从数据库返回一行,多行或没有行。

然后:

if (items.Any()) {
    //do something, but only if there are items
    foreach (var item in items) {
      ...
    }
    //do something else, but only if there are items
}

因此,如果有项目,我们将执行两个动作和一个循环。假设通常是返回的项目,将上述代码编辑为更有意义:

var items = GetItems().ToList();

所以我的Any()(有时甚至是.Count() > 0

您如何看待这个?假设GetItems()返回一个复杂的查询,这个查询本身并不慢,但仍然很复杂。

2 个答案:

答案 0 :(得分:2)

如果性能至关重要并且您不希望一次性将所有内容加载到内存中,则可以使用这种不需要多次执行查询的方法:

bool anyItems = false; bool firstItem = true;
foreach (var item in items) 
{
    anyItems = true;
    if(firstItem)
    {
       //do something, but only if there are items and only once
        firstItem = false;
    }
    // do something with this item
}
if(anyItems)
{
    //do something else, but only if there are items
} 

如果您不希望使用ToList多个项目,那么您就不需要关心多个AnyCount来电,您甚至可以访问给定索引处的项目(for循环中的fe)。

所以ToList会花费内存,但

  • 为您提供项目的未连接快照程序
  • 让您的代码更易于阅读
  • 可以使用索引器或for-loop

使用IQueryable可以节省内存,但

  • 始终为您提供当前状态(items.Any可能会在以后产生不同的结果)
  • 代码的可读性较差,如上所示
  • 就像一个流,所以你不能使用for循环或索引器

答案 1 :(得分:1)

你最好这样做:

bool anyItems = false;
foreach (var item in items) {
    anyItems = true;
    // do stuff       
}

这样你只执行一次查询而不是一次将所有项目都拉入内存。如果你真的不需要知道是否有物品 - 你可以删除anyItems旗帜。

如果你需要在处理项目之前做一些事情 - 在循环的第一次迭代中执行此操作,然后再处理第一项:

bool firstItem = true;
foreach (var item in items) {
    if (firstItem) {
        // do something, but only if there are items
        firstItem = false;
    }
    // handle item          
}

如果这会带来很多好处,取决于你的情况。如果您不期望成千上万的项目 - 您可以使用ToList。如果您希望很多这些查询返回0项 - 您可能更喜欢进行Any次查询,但前提是它们要快得多(您应该自己测量)。如果您不希望大多数查询返回0项 - 最好始终使用此方法(或ToList)来保存一个数据库查询。